Spring源碼分析之AOP從解析到調(diào)用

正文:

在上一篇,我們對IOC核心部分流程已經(jīng)分析完畢,相信小伙伴們有所收獲,從這一篇開始,我們將會踏上新的旅程,即Spring的另一核心:AOP!

首先,為了讓大家能更有效的理解AOP,先帶大家過一下AOP中的術(shù)語:

  • 切面(Aspect):指關(guān)注點模塊化,這個關(guān)注點可能會橫切多個對象。事務(wù)管理是企業(yè)級Java應(yīng)用中有關(guān)橫切關(guān)注點的例子。在Spring AOP中,切面可以使用在普通類中以@Aspect注解來實現(xiàn)。
  • 連接點(Join point):在Spring AOP中,一個連接點總是代表一個方法的執(zhí)行,其實就代表增強的方法。
  • 通知(Advice):在切面的某個特定的連接點上執(zhí)行的動作。通知有多種類型,包括aroundbeforeafter等等。許多AOP框架,包括Spring在內(nèi),都是以攔截器做通知模型的,并維護(hù)著一個以連接點為中心的攔截器鏈。
  • 目標(biāo)對象(Target):目標(biāo)對象指將要被增強的對象。即包含主業(yè)務(wù)邏輯的類的對象。
  • 切點(Pointcut):匹配連接點的斷言。通知和切點表達(dá)式相關(guān)聯(lián),并在滿足這個切點的連接點上運行(例如,當(dāng)執(zhí)行某個特定名稱的方法時)。切點表達(dá)式如何和連接點匹配是AOP的核心:Spring默認(rèn)使用AspectJ切點語義。
  • 顧問(Advisor): 顧問是Advice的一種包裝體現(xiàn),Advisor是Pointcut以及Advice的一個結(jié)合,用來管理Advice和Pointcut。
  • 織入(Weaving):將通知切入連接點的過程叫織入
  • 引入(Introductions):可以將其他接口和實現(xiàn)動態(tài)引入到targetClass中

一個栗子

術(shù)語看完了,我們先上個Demo回顧一下吧~

  1. 首先,使用EnableAspectJAutoProxy注解開啟我們的AOP

    @ComponentScan(basePackages = {"com.my.spring.test.aop"})
    @Configuration
    @EnableAspectJAutoProxy
    public class Main {
    
     public static void main(String[] args) {
         AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
         IService service = context.getBean("service", IService.class);
         service.doService();
     }
    }
    
  2. 寫一個接口

    public interface IService {
    
     void doService();
    }
    
  3. 寫一個實現(xiàn)類

    @Service("service")
    public class ServiceImpl implements IService{
    
     @Override
     public void doService() {
         System.out.println("do service ...");
     }
    }
    
  4. 寫一個切面

    @Aspect
    @Component
    public class ServiceAspect {
    
     @Pointcut(value = "execution(* com.my.spring.test.aop.*.*(..))")
     public void pointCut() {
     }
    
     @Before(value = "pointCut()")
     public void methodBefore(JoinPoint joinPoint) {
         String methodName = joinPoint.getSignature().getName();
         System.out.println("執(zhí)行目標(biāo)方法 【" + methodName + "】 的【前置通知】,入?yún)ⅲ? + Arrays.toString(joinPoint.getArgs()));
     }
    
     @After(value = "pointCut()")
     public void methodAfter(JoinPoint joinPoint) {
         String methodName = joinPoint.getSignature().getName();
         System.out.println("執(zhí)行目標(biāo)方法 【" + methodName + "】 的【后置通知】,入?yún)ⅲ? + Arrays.toString(joinPoint.getArgs()));
     }
    
     @AfterReturning(value = "pointCut()")
     public void methodReturn(JoinPoint joinPoint) {
         String methodName = joinPoint.getSignature().getName();
         System.out.println("執(zhí)行目標(biāo)方法 【" + methodName + "】 的【返回通知】,入?yún)ⅲ? + Arrays.toString(joinPoint.getArgs()));
     }
    
     @AfterThrowing(value = "pointCut()")
     public void methodThrow(JoinPoint joinPoint) {
         String methodName = joinPoint.getSignature().getName();
         System.out.println("執(zhí)行目標(biāo)方法 【" + methodName + "】 的【異常通知】,入?yún)ⅲ? + Arrays.toString(joinPoint.getArgs()));
     }
    }
    
  5. 測試運行

    執(zhí)行目標(biāo)方法 【doService】 的【前置通知】,入?yún)ⅲ篬]
    do service ...
    執(zhí)行目標(biāo)方法 【doService】 的【返回通知】,入?yún)ⅲ篬]
    執(zhí)行目標(biāo)方法 【doService】 的【后置通知】,入?yún)ⅲ篬]
    

以上

Demo看完了,運行效果也出來了,AOP已生效,但如何生效的呢?相比于我們普通使用Bean的Demo,在這里,我們只不過加上了一個@EnableAspectJAutoProxy注解以及一個標(biāo)識了@Aspectj的類,那么我們先看看@EnableAspectJAutoProxy這個注解做了什么吧~

開啟AOP

以下是筆者所畫的大致流程圖

? 其中AspectJAutoProxyRegistrar實現(xiàn)了ImportBeanDefinitionRegistrar,所以在處理BeanFactoryPostProcessor邏輯時將會調(diào)用registerBeanDefinitions方法,此時就會把AnnotationAwareAspectJAutoProxyCreator注冊到容器中,其中BeanFactoryPostProcessor的邏輯就不再說了,往期文章有過詳細(xì)分析。而AnnotationAwareAspectJAutoProxyCreator的類圖如下:

我們發(fā)現(xiàn)AnnotationAwareAspectJAutoProxyCreator是實現(xiàn)了BeanPostProcessor接口的類,所以它其實是一個后置處理器,那么,還記得在創(chuàng)建Bean過程中的BeanPostProcessor九次調(diào)用時機嗎?不記得也沒關(guān)系,AnnotationAwareAspectJAutoProxyCreator起作用的地方是在bean的實例化前以及初始化后,分別對應(yīng)著解析切面和創(chuàng)建動態(tài)代理的過程,現(xiàn)在,就讓我們先來看看解析切面的過程吧~

解析切面

解析切面的流程如下圖所示:

我們已經(jīng)了解到切面解析的過程是由AnnotationAwareAspectJAutoProxyCreator完成的,而AnnotationAwareAspectJAutoProxyCreator又繼承了AbstractAutoProxyCreator,所以首先,我們先會來到AbstractAutoProxyCreator#postProcessBeforeInstantiation

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    // class類型是否為(Advice, Pointcut, Advisor, AopInfrastructureBean)
  // shouldSkip中將會解析切面
  if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return null;
  }
}

調(diào)用到子類的AspectJAwareAdvisorAutoProxyCreator#shouldSkip

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
  // 尋找advisor
  List<Advisor> candidateAdvisors = findCandidateAdvisors();
  for (Advisor advisor : candidateAdvisors) {
    if (advisor instanceof AspectJPointcutAdvisor &&
        ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
      return true;
    }
  }
  return super.shouldSkip(beanClass, beanName);
}

findCandidateAdvisors

protected List<Advisor> findCandidateAdvisors() {
  // 尋找實現(xiàn)了Advisor接口的類, 由于我們一般不會以接口的方式實現(xiàn)切面,這里返回null
  List<Advisor> advisors = super.findCandidateAdvisors();
  if (this.aspectJAdvisorsBuilder != null) {
    // 這里將解析出所有的切面
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  }
  return advisors;
}

buildAspectJAdvisors

public List<Advisor> buildAspectJAdvisors() {
  // aspectBeanNames有值則說明切面已解析完畢
  List<String> aspectNames = this.aspectBeanNames;
  // Double Check
  if (aspectNames == null) {
    synchronized (this) {
      aspectNames = this.aspectBeanNames;
      if (aspectNames == null) {
        List<Advisor> advisors = new ArrayList<>();
        aspectNames = new ArrayList<>();
        // 取出是Object子類的bean,其實就是所有的bean
        String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
          this.beanFactory, Object.class, true, false);
        for (String beanName : beanNames) {
          // 獲得該bean的class
          Class<?> beanType = this.beanFactory.getType(beanName);
          // 判斷是否有標(biāo)識@AspectJ注解
          if (this.advisorFactory.isAspect(beanType)) {
            // 將beanName放入集合中
            aspectNames.add(beanName);
            // 將beanType和beanName封裝到AspectMetadata中
            AspectMetadata amd = new AspectMetadata(beanType, beanName);
            // Kind默認(rèn)為SINGLETON
            if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
              MetadataAwareAspectInstanceFactory factory =
                new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
              // 這里會通過@Before @After等標(biāo)識的方法獲取到所有的advisor
              List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
              if (this.beanFactory.isSingleton(beanName)) {
                // 將獲取到的所有advisor放入緩存
                this.advisorsCache.put(beanName, classAdvisors);
              }
              advisors.addAll(classAdvisors);
            }
          }
        }
        // 將所有解析過的beanName賦值
        this.aspectBeanNames = aspectNames;
        return advisors;
      }
    }
  }
  // aspectNames不為空,意味有advisor,取出之前解析好的所有advisor
  List<Advisor> advisors = new ArrayList<>();
  // 獲取到所有解析好的advisor
  for (String aspectName : aspectNames) {
    List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
    if (cachedAdvisors != null) {
      advisors.addAll(cachedAdvisors);
    }
        return advisors;
    }

advisorFactory.getAdvisors

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 獲取到標(biāo)識了@AspectJ的class,其實就是剛剛封裝的class
  Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
  // 獲取className
  String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
  
  List<Advisor> advisors = new ArrayList<>();
  
  // 拿出該類除了標(biāo)識@PointCut的所有方法進(jìn)行遍歷 getAdvisorMethods時會對method進(jìn)行一次排序
  // 排序順序 Around, Before, After, AfterReturning, AfterThrowing
  for (Method method : getAdvisorMethods(aspectClass)) {
    // 獲取到advisor
    Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
    if (advisor != null) {
      // 加入到集合中
      advisors.add(advisor);
    }
  }
}

我們先看下getAdvisorMethods方法

private List<Method> getAdvisorMethods(Class<?> aspectClass) {
  final List<Method> methods = new ArrayList<>();
  // 循環(huán)遍歷該類和父類的所有方法
  ReflectionUtils.doWithMethods(aspectClass, method -> {
    // 排除@PointCut標(biāo)識的方法
    if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
      methods.add(method);
    }
  }, ReflectionUtils.USER_DECLARED_METHODS);
  if (methods.size() > 1) {
    // 以Around, Before, After, AfterReturning, AfterThrowing的順序自定義排序
    methods.sort(METHOD_COMPARATOR);
  }
  return methods;
}

不知道小伙伴們對ReflectionUtils.doWithMethods這個工具類熟不熟悉呢,這個工具類在之前分析Bean創(chuàng)建過程時可是出現(xiàn)了好多次呢,并且我們也是可以使用的

現(xiàn)在,已經(jīng)獲取到切面中的所有方法了,那么接下來就該對這些方法解析并進(jìn)行封裝成advisor了~

getAdvisor

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
            int declarationOrderInAspect, String aspectName) {
    // 獲取方法上的切點表達(dá)式
  AspectJExpressionPointcut expressionPointcut = getPointcut(
    candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
  // 封裝成對象返回,創(chuàng)建對象時將會解析方法創(chuàng)建advice
  return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                                                        this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

獲取切點表達(dá)式的過程其實非常簡單,即是解析方法上的注解,取出注解上的value即可

getPointcut

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
  // 查找方法上和AspectJ相關(guān)注解
  AspectJAnnotation<?> aspectJAnnotation =
    AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  // 設(shè)置切點表達(dá)式
  AspectJExpressionPointcut ajexp =
    new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
  // PointcutExpression 為注解上value屬性的值
  ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
  if (this.beanFactory != null) {
    ajexp.setBeanFactory(this.beanFactory);
  }
  return ajexp;
}

new InstantiationModelAwarePointcutAdvisorImpl,在這里,才會真正創(chuàng)建出advice

public InstantiationModelAwarePointcutAdvisorImpl(){
  //...省略賦值過程...
  // 實例化出advice
  this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
  // 獲取advice,aspectJAdviceMethod為方法,aspectName為切面類
  Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
                                                       this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
  return (advice != null ? advice : EMPTY_ADVICE);
}
public Advice getAdvice(){
  // 根據(jù)方法獲取到注解信息
  AspectJAnnotation<?> aspectJAnnotation =
                AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  AbstractAspectJAdvice springAdvice;
  // 根據(jù)注解類型返回對象,創(chuàng)建對象的過程都是一樣的,都是調(diào)用父類的構(gòu)造方法
  // candidateAdviceMethod為切面的方法,expressionPointcut是切點
  switch (aspectJAnnotation.getAnnotationType()) {
    case AtPointcut
      return null;
    case AtAround:
      springAdvice = new AspectJAroundAdvice(
        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
    case AtBefore:
      springAdvice = new AspectJMethodBeforeAdvice(
        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
    case AtAfter:
      springAdvice = new AspectJAfterAdvice(
        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
      //...省略其他的advice
    default:
      throw new UnsupportedOperationException(
        "Unsupported advice type on method: " + candidateAdviceMethod);
  }
  return springAdvice;
}

springAdvice已創(chuàng)建完畢,意味著切面中的某個方法已經(jīng)解析完畢了,其他的方法解析過程大致也是相似的

小結(jié)

其實解析切面本身并不復(fù)雜,只是Spring中將切面類封裝來封裝去容易使人混亂,如buildAspectJAdvisors方法中,封裝了一個AspectMetadata amd = new AspectMetadata(beanType, beanName);,又立即發(fā)起判定amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON,其實這里完全可以變?yōu)?code>AjTypeSystem.getAjType(currClass).getPerClause().getKind() == PerClauseKind.SINGLETON,AjTypeSystem.getAjType(currClass)new AspectMetadata的一部分邏輯,筆者這里給大家總結(jié)一下吧。

首先,循環(huán)所有的beanName,找到帶有@Aspectj注解的class, 獲取到class中的所有方法進(jìn)行遍歷解析,取出方法注解上的值(切點:pointcut),然后把方法,切點表達(dá)式,封裝了BeanFactory,BeanName的factory封裝成相應(yīng)的SpringAdvice, 由SpringAdvice和pointcut組合成一個advisor。

創(chuàng)建代理對象

切面已經(jīng)解析完畢,接下來,我們就來看看如何把解析出的切面織入到目標(biāo)方法中吧

但,在這之前,還有必要給小伙伴們補充一點前置知識。

我們知道,一個bean是否能夠被aop代理,取決于它是否滿足代理條件,即為是否能夠被切點表達(dá)式所命中,而在Spring AOP中,bean與切點表達(dá)式進(jìn)行匹配的是AspectJ實現(xiàn)的,并非Spring所完成的,所以我們先來看看AspectJ如何匹配出合適的bean的吧

栗子

首先需要引入org.aspectj:aspectjweaver依賴

一個Service,包名為com.my.spring.test.aop

package com.my.spring.test.aop;

/**
 * 切點表達(dá)式可以匹配的類
 *
 */
public class ServiceImpl{
    /**
     * 切點表達(dá)式可以匹配的方法
     */
  public void doService() {
    System.out.println("do service ...");
  }
    public void matchMethod() {
        System.out.println("ServiceImpl.notMatchMethod");
    }
}

然后,我們自己封裝一個用于匹配的工具類,具體功能大家看注釋哈哈

package com.my.spring.test.aspectj;

import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.ShadowMatch;

import java.lang.reflect.Method;

/**
 * aop工具
 */
public class AOPUtils {
    // AspectJ的固定寫法,獲取一個切點解析器
    static PointcutParser parser = PointcutParser
            .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
                    PointcutParser.getAllSupportedPointcutPrimitives(), ClassLoader.getSystemClassLoader());
    // 切點表達(dá)式
    private static PointcutExpression pointcutExpression;

    /**
     * 初始化工具類,我們需要先獲取一個切點表達(dá)式
     *
     * @param expression 表達(dá)式
     */
    public static void init(String expression){
        // 解析出一個切點表達(dá)式
        pointcutExpression =  parser.parsePointcutExpression(expression);
    }

    /**
     * 第一次篩選,根據(jù)類篩選,也叫做粗篩
     *
     * @param targetClass 目標(biāo)類
     * @return 是否匹配
     */
    public static boolean firstMatch(Class<?> targetClass){
    // 根據(jù)類篩選
        return pointcutExpression.couldMatchJoinPointsInType(targetClass);
    }

    /**
     * 第二次篩選,根據(jù)方法篩選,也叫做精篩,精篩通過則說明完全匹配
     * ps: 也可以使用該方法進(jìn)行精篩,粗篩的目的是提高性能,第一次直接過濾掉不合適的類再慢慢精篩
     * 
     * @param method 方法
     * @return 是否匹配
     */
    public static boolean lastMatch(Method method){
    // 根據(jù)方法篩選
        ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
        return shadowMatch.alwaysMatches();
    }

}

測試

public class AOPUtilsTest {

    public static void main(String[] args) throws NoSuchMethodException {
        // 定義表達(dá)式
        String expression = "execution(* com.my.spring.test.aop.*.*(..))";
        // 初始化工具類
        AOPUtils.init(expression);
        // 粗篩
        boolean firstMatch = AOPUtils.firstMatch(ServiceImpl.class);
        if(firstMatch){
            System.out.println("第一次篩選通過");
            // 正常情況應(yīng)該是獲取所有方法進(jìn)行遍歷,我這里偷懶了~
            Method doService = ServiceImpl.class.getDeclaredMethod("doService");
            // 精篩
            boolean lastMatch = AOPUtils.lastMatch(doService);
            if(lastMatch){
                System.out.println("第二次篩選通過");
            }
            else{
                System.out.println("第二次篩選未通過");
            }
        }
        else {
            System.out.println("第一次篩選未通過");
        }
    }
}

結(jié)果(就不截圖了,懷疑的小伙伴可以自己試試~)

第一次篩選通過
第二次篩選通過

當(dāng)我們新建一個類Test,把切點表達(dá)式換成

execution(* com.my.spring.test.aop.Test.*(..))

測試結(jié)果為

第一次篩選未通過

再把切點表達(dá)式換成指定的方法

execution(* com.my.spring.test.aop.*.matchMethod(..))

結(jié)果

第一次篩選通過
第二次篩選未通過

到這里,小伙伴們應(yīng)該明白了AspectJ的使用方法吧

代理對象創(chuàng)建過程

接下來,我們就來看看Spring是如何使用AspectJ匹配出相應(yīng)的advisor并創(chuàng)建代理對象的吧,以下為創(chuàng)建代理對象的大致路程圖

創(chuàng)建代理對象是在bean初始化后完成的,所以對應(yīng)的beanPostProcessor調(diào)用時機為postProcessAfterInitialization

AbstractAutoProxyCreator#postProcessAfterInitialization

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            // 獲取緩存key值,其實就是beanName
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            // 判斷緩存中是否有該對象,有則說明該對象已被動態(tài)代理,跳過
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

wrapIfNecessary

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 根據(jù)bean獲取到匹配的advisor
  Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  if (specificInterceptors != DO_NOT_PROXY) {
    // 創(chuàng)建代理對象
    Object proxy = createProxy(
      bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    return proxy;
  }
  return bean;
}

getAdvicesAndAdvisorsForBean

protected Object[] getAdvicesAndAdvisorsForBean(
            Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
  // 獲取合適的advisor
  List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
  return advisors.toArray();
}

findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  // 先獲取到所有的advisor, 這里和解析過程相同,由于已經(jīng)解析好,所以會直接從緩存中取出
  List<Advisor> candidateAdvisors = findCandidateAdvisors();
  // 篩選出匹配的advisor
  List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  // 增加一個默認(rèn)的advisor
  extendAdvisors(eligibleAdvisors);
  if (!eligibleAdvisors.isEmpty()) {
    // 排序
    eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  }
  return eligibleAdvisors;
}

findAdvisorsThatCanApply

protected List<Advisor> findAdvisorsThatCanApply(
            List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
  // 查找匹配的advisor
  return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}

findAdvisorsThatCanApply

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz){
  List<Advisor> eligibleAdvisors = new ArrayList<>();
  for (Advisor candidate : candidateAdvisors) {
    // 判斷是否匹配
    if (canApply(candidate, clazz, hasIntroductions)) {
      // 加入到合適的advisors集合中
      eligibleAdvisors.add(candidate);
    }
  }
  return eligibleAdvisors;
}

canApply

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
  if (advisor instanceof PointcutAdvisor) {
    PointcutAdvisor pca = (PointcutAdvisor) advisor;
    // 判斷是否匹配
    return canApply(pca.getPointcut(), targetClass, hasIntroductions);
  }
  else {
    // It doesn't have a pointcut so we assume it applies.
    return true;
  }
}

canApply

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    // 第一次篩選,對class篩選判斷是否滿足匹配條件
  // 這里將會初始化切點表達(dá)式
  if (!pc.getClassFilter().matches(targetClass)) {
    return false;
  }
  
  IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
  if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
    introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
  }
  
  for (Class<?> clazz : classes) {
    Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
    // 循環(huán)所有方法進(jìn)行第二次篩選,判斷是否有方法滿足匹配條件
    for (Method method : methods) {
      if (introductionAwareMethodMatcher != null ?
          introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
          methodMatcher.matches(method, targetClass)) {
        return true;
      }
    }
  }
  return false;
}

pc.getClassFilter()

public ClassFilter getClassFilter() {
  obtainPointcutExpression();
  return this;
}

obtainPointcutExpression

private PointcutExpression obtainPointcutExpression() {
  if (this.pointcutExpression == null) {
    // 確認(rèn)類加載器
    this.pointcutClassLoader = determinePointcutClassLoader();
    // 創(chuàng)建切點表達(dá)式
    this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
  }
  return this.pointcutExpression;
}

buildPointcutExpression

private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {
  // 初始化切點解析器
  PointcutParser parser = initializePointcutParser(classLoader);
  PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
  for (int i = 0; i < pointcutParameters.length; i++) {
    pointcutParameters[i] = parser.createPointcutParameter(
      this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
  }
  // 使用切點解析器進(jìn)行解析表達(dá)式獲取切點表達(dá)式
  return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),
                                        this.pointcutDeclarationScope, pointcutParameters);
}

initializePointcutParser

private PointcutParser initializePointcutParser(@Nullable ClassLoader classLoader) {
  // 獲得切點解析器
  PointcutParser parser = PointcutParser
    .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
    SUPPORTED_PRIMITIVES, classLoader);
  parser.registerPointcutDesignatorHandler(new BeanPointcutDesignatorHandler());
  return parser;
}

pc.getClassFilter便是完成了以上事情,此時再進(jìn)行調(diào)用matchs方法

public boolean matches(Class<?> targetClass) {
  PointcutExpression pointcutExpression = obtainPointcutExpression();
  // 使用切點表達(dá)式進(jìn)行粗篩
  return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}

introductionAwareMethodMatcher.matches 同樣如此

以上便是尋找合適的advisor的過程,下面,就是通過這些advisor進(jìn)行創(chuàng)建動態(tài)代理了

createProxy

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
            @Nullable Object[] specificInterceptors, TargetSource targetSource) {
  ProxyFactory proxyFactory = new ProxyFactory();
  proxyFactory.copyFrom(this);
    // 將specificInterceptors(現(xiàn)在是Object)轉(zhuǎn)化為Advisor返回
  Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
  // 賦值到proxyFactory的advisors屬性中
  proxyFactory.addAdvisors(advisors);
  proxyFactory.setTargetSource(targetSource);
  customizeProxyFactory(proxyFactory);
  // 創(chuàng)建動態(tài)代理
  return proxyFactory.getProxy(getProxyClassLoader());
}

proxyFactory.getProxy

public Object getProxy(@Nullable ClassLoader classLoader) {
  // 創(chuàng)建代理對象
  return createAopProxy().getProxy(classLoader);
}

createAopProxy

protected final synchronized AopProxy createAopProxy() {
  // 創(chuàng)建AOP代理對象
  return getAopProxyFactory().createAopProxy(this);
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  // @EnableAspectJAutoProxy的proxyTargetClass是否配置為true
  if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    Class<?> targetClass = config.getTargetClass();
    if (targetClass == null) {
      throw new AopConfigException("TargetSource cannot determine target class: " +
                                   "Either an interface or a target is required for proxy creation.");
    }
    // 如何是接口則創(chuàng)建jdk動態(tài)代理
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
      return new JdkDynamicAopProxy(config);
    }
    // cglib動態(tài)代理
    return new ObjenesisCglibAopProxy(config);
  }
  // 默認(rèn)是jdk動態(tài)代理
  else {
    return new JdkDynamicAopProxy(config);
  }
}
public Object getProxy(@Nullable ClassLoader classLoader) {
  // 獲取到代理的接口
  Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
  findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
  // 創(chuàng)建jdk代理,傳入的為JdkDynamicAopProxy對象,里面包含了被代理的bean以及匹配的advisor
  return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

動態(tài)代理創(chuàng)建完成~

代理對象調(diào)用過程

對象都給你創(chuàng)建好了,接下當(dāng)然是開..發(fā)起調(diào)用咯

以下是調(diào)用的大致流程圖

代理對象被調(diào)用的是invoke方法,我們所創(chuàng)建的代理對象為JdkDynamicAopProxy,所以

JdkDynamicAopProxy#invoke

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  Object oldProxy = null;
  boolean setProxyContext = false;
  // 取出包裝了被代理bean的對象->創(chuàng)建代理對象時的SingletonTargetSource, advised為ProxyFactory
  TargetSource targetSource = this.advised.targetSource;
  Object target = null;
  // 拿到bean
  target = targetSource.getTarget();
  Class<?> targetClass = (target != null ? target.getClass() : null);
  // 將所有advisor中的advice取出,并轉(zhuǎn)化為對應(yīng)的interceptor
  List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  // 創(chuàng)建一個最外層的MethodInvocation用于發(fā)起調(diào)用
  MethodInvocation invocation =
    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
  // 發(fā)起鏈?zhǔn)秸{(diào)用
  Object retVal = invocation.proceed();
  return retVal;
}

我們先看獲取interceptor的過程

getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
  // 將所有advisor中的advice取出并封裝成intercept
  return this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
}
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
  Advised config, Method method, @Nullable Class<?> targetClass) {
    // 創(chuàng)建一個advisor適配器的注冊器用于轉(zhuǎn)化advice,創(chuàng)建時將默認(rèn)注冊三個適配器
  AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
  Advisor[] advisors = config.getAdvisors();
  // 循環(huán)遍歷所有advisor
  for (Advisor advisor : advisors) {
    // 將advisor中的advice轉(zhuǎn)化為interceptor
    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
    interceptorList.addAll(Arrays.asList(interceptors));
    return interceptorList;
  }
}

GlobalAdvisorAdapterRegistry.getInstance() 類初始化時調(diào)用靜態(tài)方法

private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry()
public static AdvisorAdapterRegistry getInstance() {
        return instance;
}
public DefaultAdvisorAdapterRegistry() {
  // 注冊三個適配器
  registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
  registerAdvisorAdapter(new AfterReturningAdviceAdapter());
  registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
  // 將適配器加入集合
  this.adapters.add(adapter);
}

registry.getInterceptors 這里面包含了advice轉(zhuǎn)化成interceptor的過程

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
  List<MethodInterceptor> interceptors = new ArrayList<>(3);
  Advice advice = advisor.getAdvice();
  // advice本身是否就是MethodInterceptor
  if (advice instanceof MethodInterceptor) {
    interceptors.add((MethodInterceptor) advice);
  }
  for (AdvisorAdapter adapter : this.adapters) {
    // 判斷advice是哪個advice 如:(advice instanceof MethodBeforeAdvice)
    if (adapter.supportsAdvice(advice)) {
      // 將advice封裝到對應(yīng)的interceptor
      interceptors.add(adapter.getInterceptor(advisor));
    }
  }
  return interceptors.toArray(new MethodInterceptor[0]);
}

若adapter為MethodBeforeAdviceAdapter,則

public MethodInterceptor getInterceptor(Advisor advisor) {
  MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
  return new MethodBeforeAdviceInterceptor(advice);
}

其他advice轉(zhuǎn)化過程相同

以上,便將所有的advice轉(zhuǎn)化成了interceptor,接下來,則是經(jīng)典的鏈?zhǔn)竭f歸調(diào)用過程

以下過程小伙伴們可以對照流程圖閱讀,畢竟遞歸還是有些復(fù)雜,需要一定的功底

ReflectiveMethodInvocation#proceed

public Object proceed() throws Throwable {
  // currentInterceptorIndex 初始值為-1
  // 當(dāng)currentInterceptorIndex等于advice的數(shù)量減一時,則調(diào)用目標(biāo)方法
  // 由于advice已排好序,所以調(diào)用順序為before, after, afterReturn, afterThrowing
  // 注意,并非調(diào)用到相應(yīng)的advice就會執(zhí)行advice方法,這里是類似遞歸調(diào)用的方式,會存在一個歸過程
  // 有些是遞的時候發(fā)起調(diào)用,如beforeAdvice, 但有些則是歸的時候發(fā)起調(diào)用,如afterAdvice
  // 遞歸的終止條件則是這下面這個return invokeJoinpoint();
  if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    return invokeJoinpoint();
  }
    // currentInterceptorIndex自增并獲取到interceptor
  Object interceptorOrInterceptionAdvice =
    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  // 將interceptro強轉(zhuǎn)為MethodInterceptor發(fā)起調(diào)用
  return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}

此時currentInterceptorIndex值為0,而我們的advice為4個(去除了默認(rèn)的),所以當(dāng)currentInterceptorIndex為3時便會調(diào)用我們的實際方法

首先調(diào)用的是MethodBeforeAdviceInterceptor

public Object invoke(MethodInvocation mi) throws Throwable {
  // 調(diào)用前置通知
  this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
  return mi.proceed();
}

mi為傳入的this,所有mi.proceed()將會回到最開始的方法

再次循環(huán),此時currentInterceptorIndex值為1

調(diào)用的是AspectJAfterAdvice

public Object invoke(MethodInvocation mi) throws Throwable {
  try {
    return mi.proceed();
  }
  finally {
    // finally意味著不管怎樣都會被調(diào)用
    invokeAdviceMethod(getJoinPointMatch(), null, null);
  }
}

繼續(xù),此時currentInterceptorIndex值為2

調(diào)用的是AfterReturningAdviceInterceptor

public Object invoke(MethodInvocation mi) throws Throwable {
  Object retVal = mi.proceed();
  this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
  return retVal;
}

繼續(xù),此時currentInterceptorIndex值為3

調(diào)用的是AspectJAfterThrowingAdvice

public Object invoke(MethodInvocation mi) throws Throwable {
  try {
    return mi.proceed();
  }
  catch (Throwable ex) {
    if (shouldInvokeOnThrowing(ex)) {
      // 調(diào)用異常通知
      invokeAdviceMethod(getJoinPointMatch(), null, ex);
    }
    // 往外拋出異常
    throw ex;
  }
}

所以如果我們的業(yè)務(wù)方法發(fā)生了異常,會調(diào)用到異常通知,而這里又把異常往外拋,所以afterReturn就會被跳過直接到after的finally方法

現(xiàn)在currentInterceptorIndex值為3了,再回調(diào)最初的方法中時,就會調(diào)用到我們的業(yè)務(wù)方法了。調(diào)用完畢則進(jìn)行歸的過程,調(diào)用過程便結(jié)束了。

以上,便是整個AOP的過程了

本篇文章中涉及到圖片的矢量圖地址為:https://www.processon.com/view/link/5fa8afdae401fd45d109f257,有需要的小伙伴可自取

下文預(yù)告:Spring源碼分析之事務(wù)管理(上)

Spring 源碼系列
  1. Spring源碼分析之 IOC 容器預(yù)啟動流程(已完結(jié))
  2. Spring源碼分析之BeanFactory體系結(jié)構(gòu)(已完結(jié))
  3. Spring源碼分析之BeanFactoryPostProcessor調(diào)用過程(已完結(jié))
  4. Spring源碼分析之Bean的創(chuàng)建過程(已完結(jié))
  5. Spring源碼分析之什么是循環(huán)依賴及解決方案(已完結(jié))
  6. Spring源碼分析之AOP從解析到調(diào)用(已完結(jié))
  7. Spring源碼分析之事務(wù)管理(上),事物管理是spring作為容器的一個特點,總結(jié)一下他的基本實現(xiàn)與原理吧
  8. Spring源碼分析之事務(wù)管理(下) ,關(guān)于他的底層事物隔離與事物傳播原理,重點分析一下
Spring Mvc 源碼系列
  1. SpringMvc體系結(jié)構(gòu)
  2. SpringMvc源碼分析之Handler解析過程
  3. SpringMvc源碼分析之請求鏈過程

另外筆者公眾號:奇客時間,有更多精彩的文章,有興趣的同學(xué),可以關(guān)注

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容