死磕Spring之AOP篇 - Spring AOP自動代理(二)篩選合適的通知器


該系列文章是本人在學習 Spring 的過程中總結下來的,里面涉及到相關源碼,可能對讀者不太友好,請結合我的源碼注釋 Spring 源碼分析 GitHub 地址 進行閱讀。

Spring 版本:5.1.14.RELEASE

在開始閱讀 Spring AOP 源碼之前,需要對 Spring IoC 有一定的了解,可查看我的 《死磕Spring之IoC篇 - 文章導讀》 這一系列文章

了解 AOP 相關術語,可先查看 《Spring AOP 常見面試題) 》 這篇文章

該系列其他文章請查看:《死磕 Spring 之 AOP 篇 - 文章導讀》

在上一篇《Spring AOP 自動代理(一)入口》文章中,分析了 Spring AOP 自動代理的入口是 AbstractAutoProxyCreator 對象,其中自動代理的過程主要分為下面兩步:

  1. 篩選出能夠應用於當前 Bean 的 Advisor
  2. 找到了合適 Advisor 則創建一個代理對象, JDK 動態代理或者 CGLIB 動態代理

本文就接着上篇文章來分析篩選合適的通知器的處理過程,包含 @AspectJAspectJ 注解的解析過程。這里的“通知器”指的是 Advisor 對象。

回顧

// AbstractAutoProxyCreator.java
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    /*
     * <1> 如果當前 Bean 已經創建過自定義 TargetSource 對象
     * 表示在上面的**實例化前置處理**中已經創建代理對象,那么直接返回這個對象
     */
    if (StringUtils.hasLength(beanName)
            && this.targetSourcedBeans.contains(beanName))
    {
        return bean;
    }
    // <2> `advisedBeans` 保存了這個 Bean 沒有必要創建代理對象,則直接返回
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    /*
     * <3> 不需要創建代理對象,則直接返回當前 Bean
     */
    if (isInfrastructureClass(bean.getClass()) // 如果是 Spring 內部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 標記接口)
            || shouldSkip(bean.getClass(), beanName)) // 應該跳過
    {
        // 將這個 Bean 不需要創建代理對象的結果保存起來
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // <4> 獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    // <5> 如果有 Advisor,則進行下面的動態代理創建過程
    if (specificInterceptors != DO_NOT_PROXY) {
        // <5.1> 將這個 Bean 已創建代理對象的結果保存至 `advisedBeans`
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // <5.2> 創建代理對象,JDK 動態代理或者 CGLIB 動態代理
        // 這里傳入的是 SingletonTargetSource 對象,可獲取代理對象的目標對象(當前 Bean)
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        // <5.3> 將代理對象的 Class 對象(目標類的子類)保存
        this.proxyTypes.put(cacheKey, proxy.getClass());
        // <5.4> 返回代理對象
        return proxy;
    }

    // <6> 否則,將這個 Bean 不需要創建代理對象的結果保存起來
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    // <7> 返回這個 Bean 對象
    return bean;
}

在創建代理對象的過程中,上面方法的第 4 步調用 getAdvicesAndAdvisorsForBean(..) 方法,獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)

// AbstractAutoProxyCreator.java
protected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,
			@Nullable TargetSource customTargetSource) throws BeansException;

抽象方法,交由子類實現

篩選出合適的 Advisor 的流程

  1. 解析出當前 IoC 容器所有 Advisor 對象

    1. 獲取當前 IoC 容器所有 Advisor 類型的 Bean

    2. 解析當前 IoC 容器中所有帶有 @AspectJ 注解的 Bean,將內部帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解的方法解析出對應的 PointcutAdvisor 對象,帶有 @DeclareParents 注解的字段解析出 IntroductionAdvisor 對象

      @Around -> AspectJAroundAdvice,實現了 MethodInterceptor

      @Before -> AspectJMethodBeforeAdvice

      @After -> AspectJAfterAdvice,實現了 MethodInterceptor

      @AfterReturning -> AspectJAfterAdvice

      @AfterThrowing -> AspectJAfterThrowingAdvice,實現了 MethodInterceptor

  2. 篩選出能夠應用於這個 Bean 的 Advisor 們,主要通過 ClassFilter 類過濾器和 MethodMatcher 方法匹配器進行匹配

  3. 對篩選出來的 Advisor 進行擴展,例如子類會往首部添加一個 PointcutAdvisor 對象

  4. 對篩選出來的 Advisor 進行排序

    • 不同的 AspectJ 根據 @Order 排序

    • 同一個 AspectJ 中不同 Advisor 的排序,優先級:AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice

主要涉及到下面幾個類:

  • AbstractAdvisorAutoProxyCreator:支持從當前 Spring 上下文獲取所有 Advisor 對象
  • AnnotationAwareAspectJAutoProxyCreator:支持從帶有 @AspectJ 注解 Bean 中解析 Advisor 對象
  • BeanFactoryAspectJAdvisorsBuilder:Advisor 構建器,用於解析出當前 BeanFactory 中所有帶有 @AspectJ 注解的 Bean 中的 Advisor
  • ReflectiveAspectJAdvisorFactory:Advisor 工廠,用於解析 @AspectJ 注解的 Bean 中的 Advisor

AnnotationAwareAspectJAutoProxyCreator 繼承 AbstractAdvisorAutoProxyCreator,借助 BeanFactoryAspectJAdvisorsBuilder 構建器,這個構建器又借助 ReflectiveAspectJAdvisorFactory 工廠。

AbstractAdvisorAutoProxyCreator

org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator:支持從當前 Spring 上下文獲取所有 Advisor 對象,存在能應用與 Bean 的 Advisor 則創建代理對象

構造函數

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {

    /** Advisor 檢索工具類 */
	@Nullable
	private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper;

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		super.setBeanFactory(beanFactory);
		if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
			throw new IllegalArgumentException(
					"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
		}
        // 初始化工作
		initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
	}

	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 設置 Advisor 檢索工具類為 BeanFactoryAdvisorRetrievalHelperAdapter
		this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
	}
}

1. getAdvicesAndAdvisorsForBean 方法

getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource),篩選某個 Bean 合適的 Advisor,如下:

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
        Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    // 獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    // 轉換成數組並返回
    return advisors.toArray();
}

調用 findEligibleAdvisors(Class<?> beanClass, String beanName) 方法,獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)

2. findEligibleAdvisors 方法

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    /*
     * <1> 解析出當前 IoC 容器所有的 Advisor 對象
     * 1. 本身是 Advisor 類型的 Bean,默認情況下都會
     * 2. 從帶有 @AspectJ 注解的 Bean 中解析出來的 Advisor,子類 AnnotationAwareAspectJAutoProxyCreator 會掃描並解析
     *    PointcutAdvisor:帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解的方法
     *       其中 Pointcut 為 AspectJExpressionPointcut,Advice 就是注解標注的方法
     *    IntroductionAdvisor:帶有 @DeclareParents 注解的字段
     *
     * 未排序,獲取到的 Advisor 在同一個 AspectJ 中的順序是根據注解來的,@Around > @Before > @After > @AfterReturning > @AfterThrowing
     */
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    /*
     * <2> 篩選出能夠應用到 `beanClass` 上面的所有 Advisor 對象並返回
     * 也就是通過 ClassFilter 進行匹配,然后再通過 MethodMatcher 對所有方法進行匹配(有一個即可)
     * AspectJExpressionPointcut 就實現了 ClassFilter 和 MethodMatcher
     */
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    /*
     * <3> 抽象方法,交由子類拓展
     * 例如 AspectJAwareAdvisorAutoProxyCreator 的實現
     * 如果 `eligibleAdvisors` 中存在和 AspectJ 相關的 Advisor
     * 則會在 `eligibleAdvisors` 首部添加一個 DefaultPointcutAdvisor 對象,對應的 Advice 為 ExposeInvocationInterceptor 對象
     * 用於暴露 MethodInvocation 對象(Joinpoint 對象),存儲在 ThreadLocal 中,在其他地方則可以使用
     */
    extendAdvisors(eligibleAdvisors);
    // <4> 對 `eligibleAdvisors` 集合進行排序,根據 @Order 注解進行排序
    if (!eligibleAdvisors.isEmpty()) {
        // 不同的 AspectJ 根據 @Order 排序
        // 同一個 AspectJ 中不同 Advisor 的排序:AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    // <5> 返回排序后的能夠應用到當前 Bean 的所有 Advisor
    return eligibleAdvisors;
}

該方法的處理過程如下:

  1. 調用 findCandidateAdvisors() 方法,解析出當前 IoC 容器所有的 Advisor 對象,得到 candidateAdvisors 集合,來源:
    • 本身是 Advisor 類型的 Bean,默認情況下都會
    • 從帶有 @AspectJ 注解的 Bean 中解析出來的 Advisor
  2. 調用 findAdvisorsThatCanApply(..) 方法,篩選出能夠應用到 beanClass 上面的所有 Advisor 對象並返回,得到 eligibleAdvisors 集合
    • 通過 ClassFilter 進行匹配,然后再通過 MethodMatcher 對所有方法進行匹配(有一個即可)
  3. 調用 extendAdvisors(List<Advisor> candidateAdvisors) 方法,對 eligibleAdvisors 進行處理
  4. 調用 sortAdvisors(List<Advisor> advisors) 方法,對 eligibleAdvisors 進行排序
  5. 返回排序后的能夠應用到當前 Bean 的所有 Advisor

接下來依次對上面的方法進行分析

2.1.1 findCandidateAdvisors 方法

findCandidateAdvisors(),該方法會去找符合條件的 Advisor 們,AbstractAdvisorAutoProxyCreator 的實現則是去找當前 IoC 容器中所有 Advisor 類型的 Bean,如下:

// AbstractAdvisorAutoProxyCreator.java
protected List<Advisor> findCandidateAdvisors() {
    Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
    // 借助 BeanFactoryAdvisorRetrievalHelperAdapter 從 IoC 容器中查找所有的 Advisor 對象
    return this.advisorRetrievalHelper.findAdvisorBeans();
}

可以看到是借助於 BeanFactoryAdvisorRetrievalHelperAdapter 去找 Advisor 類型的 Bean,如下:

// BeanFactoryAdvisorRetrievalHelperAdapter.java
public List<Advisor> findAdvisorBeans() {
    // Determine list of advisor bean names, if not cached already.
    // <1> 先從緩存中獲取所有 Advisor
    String[] advisorNames = this.cachedAdvisorBeanNames;
    // <2> 沒有緩存
    if (advisorNames == null) {
        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the auto-proxy creator apply to them!
        // <2.1> 從當前 BeanFactory 容器中找到所有 Advisor 類型的 bean 的名稱
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this.beanFactory, Advisor.class, true, false);
        // <2.2> 放入緩存中
        this.cachedAdvisorBeanNames = advisorNames;
    }
    // <3> 如果沒有 Advisor,則返回一個空集合
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    List<Advisor> advisors = new ArrayList<>();
    /*
     * <4> 遍歷所有的 Advisor 類型的 Bean 的名稱,獲取對應的 Bean
     */
    for (String name : advisorNames) {
        // <4.1> 判斷這個 Bean 是否有資格,默認為 true
        if (isEligibleBean(name)) {
            // <4.2> 正在初始化,則先跳過
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Skipping currently created advisor '" + name + "'");
                }
            }
            // <4.3> 否則,獲取對應的 Bean
            else {
                try {
                    // 依賴查找到這個 Advisor 對象
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {
                    Throwable rootCause = ex.getMostSpecificCause();
                    // ...
                    throw ex;
                }
            }
        }
    }
    // <5> 返回 IoC 容器中所有的 Advisor
    return advisors;
}

該方法的處理過程如下:

  1. 先從緩存中獲取所有 Advisor

  2. 沒有緩存

    1. 從當前 BeanFactory 容器中找到所有 Advisor 類型的 Bean 的名稱
    2. 放入緩存中
  3. 如果沒有 Advisor,則返回一個空集合

  4. 遍歷所有的 Advisor 類型的 Bean 的名稱,獲取對應的 Bean

    1. 判斷這個 Bean 是否有資格,默認為 true
    2. 正在初始化,則先跳過
    3. 否則,獲取對應的 Bean,依賴查找到這個 Advisor 對象
  5. 返回 IoC 容器中所有的 Advisor

總結下來,就是從當前 Spring IoC 容器中找到所有 Advisor 類型的 Bean

2.2 findAdvisorsThatCanApply 方法

findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) 方法,從 candidateAdvisors 中找到能夠應用於 beanClass 的 Advisor,如下:

protected List<Advisor> findAdvisorsThatCanApply(
        List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
        /*
         * 篩選出能夠應用到 `beanClass` 上面的所有 Advisor 對象並返回
         * 也就是通過 ClassFilter 進行匹配,然后再通過 MethodMatcher 對所有方法進行匹配(有一個即可)
         * AspectJExpressionPointcut 就實現了 ClassFilter 和 MethodMatcher
         */
        return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    }
    finally {
        ProxyCreationContext.setCurrentProxiedBeanName(null);
    }
}

可以看到是借助於 AopUtils 工具類從 candidateAdvisors 中找到能夠應用於 beanClass 的 Advisor,如下:

// AopUtils.java
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
    }
    List<Advisor> eligibleAdvisors = new ArrayList<>();
    /*
     * <1> 遍歷所有的 Advisor 對象
     * 找到能夠應用當前 Bean 的 IntroductionAdvisor 對象,放入 `eligibleAdvisors` 集合中
     */
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor // 如果是 IntroductionAdvisor 類型
                && canApply(candidate, clazz)) // 且能夠應用到當前 Bean 中,通過其 ClassFilter 進行過濾
        {
            eligibleAdvisors.add(candidate);
        }
    }
    boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    /*
     * <2> 遍歷所有的 Advisor 對象
     * 如果是 IntroductionAdvisor 類型,則會跳過,因為上面已經判斷過
     * 找到能夠應用當前 Bean 的 Advisor 對象,放入 `eligibleAdvisors` 集合中
     */
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor) {
            // already processed
            continue;
        }
        // 判斷是否能夠應用到這個 Bean 上面
        if (canApply(candidate, clazz, hasIntroductions)) {
            eligibleAdvisors.add(candidate);
        }
    }
    // <3> 返回能夠應用到當前 Bean 的所有 Advisor 對象
    return eligibleAdvisors;
}

該方法的處理過程如下:

  1. 遍歷所有的 Advisor 對象,找到能夠應用當前 Bean 的 IntroductionAdvisor 對象,放入 eligibleAdvisors 集合中,需要滿足下面兩個條件

    • IntroductionAdvisor 類型
    • 能夠應用到當前 Bean 中,通過其 ClassFilter 進行過濾
  2. 遍歷所有的 Advisor 對象,找到能夠應用當前 Bean 的 Advisor 對象,放入 eligibleAdvisors 集合中;如果是 IntroductionAdvisor 類型,則會跳過,因為上面已經判斷過

  3. 返回能夠應用到當前 Bean 的所有 Advisor 對象

AopUtils#canApply 方法

如何判斷這個 Advisor 能夠應用於某個 Bean 都是調用 canApply(..) 方法如下:

// AopUtils.java
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    if (advisor instanceof IntroductionAdvisor) {
        /*
         * 從 IntroductionAdvisor 中獲取 ClassFilter 類過濾器,判斷這個目標類是否符合條件
         */
        return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
    }
    else if (advisor instanceof PointcutAdvisor) {
        /*
         * 根據 Pointcut 中的 ClassFilter 和 MethodFilter 進行過濾
         * 例如 Aspect 的實現類 AspectJExpressionPointcut
         */
        PointcutAdvisor pca = (PointcutAdvisor) advisor;
        return canApply(pca.getPointcut(), targetClass, hasIntroductions);
    }
    else {
        // It doesn't have a pointcut so we assume it applies.
        // 否則,沒有 Pointcut,也就是沒有篩選條件,則都符合條件
        return true;
    }
}

如果 IntroductionAdvisor 類型的 Advisor 則通過 ClassFilter 類過濾器進行判斷即可;如果是 PointcutAdvisor 類型的 Advisor 則需要調用 canApply(..) 的重載方法進行判斷;否則,沒有 Pointcut,也就是沒有篩選條件,則都符合條件

AopUtils#canApply 重載方法

如何判斷 PointcutAdvisor 類型的 Advisor 能夠應用於某個 Bean 的過程如下:

// AopUtils.java
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    Assert.notNull(pc, "Pointcut must not be null");
    // <1> 使用 ClassFilter 匹配 `targetClass`
    if (!pc.getClassFilter().matches(targetClass)) {
        return false;
    }

    // <2> 獲取 MethodMatcher 方法匹配器
    MethodMatcher methodMatcher = pc.getMethodMatcher();
    // <3> 如果方法匹配器為 TrueMethodMatcher,則默認都通過
    if (methodMatcher == MethodMatcher.TRUE) {
        // No need to iterate the methods if we're matching any method anyway...
        return true;
    }

    // <4> 如果方法匹配器為 IntroductionAwareMethodMatcher,則進行轉換
    // AspectJExpressionPointcut 就是 IntroductionAwareMethodMatcher 的實現類
    IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
    if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
        introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
    }

    /*
     * <5> 獲取目標類、以及實現的所有接口,並添加至 `classes` 集合中
     */
    Set<Class<?>> classes = new LinkedHashSet<>();
    // <5.1> 如果不是 java.lang.reflect.Proxy 的子類
    if (!Proxy.isProxyClass(targetClass)) {
        // 獲取目標類的 Class 對象(如果目標類是 CGLIB 代理對象,則獲取其父類的 Class 對象,也就得到了目標類)
        classes.add(ClassUtils.getUserClass(targetClass));
    }
    // <5.2> 獲取目標類實現的所有接口,如果目標類本身是一個接口,那么就取這個目標類
    classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

    /*
     * <6> 遍歷上面的 `classes` 集合
     */
    for (Class<?> clazz : classes) {
        // <6.1> 獲取這個 Class 對象的所有方法
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        // <6.2> 遍歷上一步獲取到的所有方法
        for (Method method : methods) {
            // <6.3> 使用方法匹配器對該方法進行匹配,如果匹配成功則直接返回 `true`
            // AspectJExpressionPointcut 底層就是通過 AspectJ 進行處理的
            if (introductionAwareMethodMatcher != null ?
                    introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                    methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }

    // <7> 一個方法都沒匹配則返回 `false`,表示這個 Advisor 不能應用到這個 Bean 上面
    return false;
}

該方法的處理過程如下:

  1. 使用 Pointcut 的 ClassFilter 匹配 targetClass,不通過則直接返回 false
  2. 獲取 Pointcut 的 MethodMatcher 方法匹配器,保存至 methodMatcher
  3. 如果 methodMatcher 為 TrueMethodMatcher,則默認都通過,返回 true
  4. 如果 methodMatcher 為 IntroductionAwareMethodMatcher,則進行轉換,保存至 introductionAwareMethodMatcher
    • AspectJExpressionPointcut 就是 IntroductionAwareMethodMatcher 的實現類
  5. 獲取目標類、以及實現的所有接口,並添加至 classes 集合中
    1. 如果不是 java.lang.reflect.Proxy 的子類,則獲取 targetClass 目標類的 Class 對象(如果目標類是 CGLIB 代理對象,則獲取其父類的 Class 對象,也就得到了目標類)
    2. 獲取 targetClass 目標類實現的所有接口,如果目標類本身是一個接口,那么就取這個目標類
  6. 遍歷上面的 classes 集合
    1. 獲取這個 Class 對象的所有方法
    2. 遍歷上一步獲取到的所有方法
    3. 使用 methodMatcher 方法匹配器對該方法進行匹配,優先使用 introductionAwareMethodMatcher 方法匹配器,匹配成功則直接返回 true,說明有一個方法滿足條件即可
      • AspectJExpressionPointcut 底層就是通過 AspectJ 的表達式處理進行處理的
  7. 一個方法都沒匹配成功則返回 false,表示這個 Advisor 不能應用到這個 Bean 上面

總結下來,PointcutAdvisor 是根據 Pointcut 的 ClassFilter 對目標類進行過濾,如果通過的話,則通過 MethodMatcher 方法匹配器對目標類的方法進行匹配,有一個方法滿足條件就表示這個 PointcutAdvisor 可以應用於目標類

2.3 extendAdvisors 方法

extendAdvisors(List<Advisor> candidateAdvisors) 放,對篩選出來的 Advisor 進行擴展,抽象方法,我們來看到子類的實現:

// AspectJAwareAdvisorAutoProxyCreator.java
@Override
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
    AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}

可以看到是借助於 AspectJProxyUtils 工具類進行擴展,如下:

public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
    // Don't add advisors to an empty list; may indicate that proxying is just not required
    if (!advisors.isEmpty()) {
        boolean foundAspectJAdvice = false;
        // 遍歷所有 Advisor
        for (Advisor advisor : advisors) {
            // Be careful not to get the Advice without a guard, as this might eagerly
            // instantiate a non-singleton AspectJ aspect...
            // 判斷這個 Advisor 是否和 AspectJ 相關
            if (isAspectJAdvice(advisor)) {
                foundAspectJAdvice = true;
                break;
            }
        }
        // 如果 `advisors` 涉及到和 AspectJ 相關的 Advisor
        // 則向其首部添加一個 DefaultPointcutAdvisor 對象,對應的 Advice 為 ExposeInvocationInterceptor 對象
        // 用於暴露 MethodInvocation 對象(Joinpoint 對象),存儲在 ThreadLocal 中,在其他地方則可以使用
        if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
            advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
            return true;
        }
    }
    return false;
}

private static boolean isAspectJAdvice(Advisor advisor) {
    return ( advisor instanceof InstantiationModelAwarePointcutAdvisor
            || advisor.getAdvice() instanceof AbstractAspectJAdvice
            || ( advisor instanceof PointcutAdvisor && ((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut) );
}

處理過程很簡單,當存在和 AspectJ 相關的 Advisor(使用了 AspectJ 的注解這里都是 true),則在首部添加一個 DefaultPointcutAdvisor 對象

添加的這個 Advisor 對應的 Advice 為 ExposeInvocationInterceptor 方法攔截器,用於暴露 MethodInvocation 對象(Joinpoint 對象),存儲在 ThreadLocal 中,在其他地方則可以使用

2.4 sortAdvisors 方法

sortAdvisors(List<Advisor> advisors) 方法,對篩選出來的 Advisor 進行排序,如下:

// AspectJAwareAdvisorAutoProxyCreator.java
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
    List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
    for (Advisor element : advisors) {
        // 使用 AspectJPrecedenceComparator 比較器
        partiallyComparableAdvisors.add(
                new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
    }
    List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
    if (sorted != null) {
        List<Advisor> result = new ArrayList<>(advisors.size());
        for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
            result.add(pcAdvisor.getAdvisor());
        }
        return result;
    }
    else {
        // AbstractAdvisorAutoProxyCreator
        // 使用 AnnotationAwareOrderComparator 比較器,通過 @Order 注解
        return super.sortAdvisors(advisors);
    }
}

AspectJPrecedenceComparator 是對 AnnotationAwareOrderComparator 的包裝,進行了擴展,排序不同類型的 Advice,詳細的過程這里不展述了

我通過 Debug 打斷點得到的結論:

  • 不同的 AspectJ 根據 @Order 排序

  • 同一個 AspectJ 中不同 Advisor 的排序,優先級如下:

    AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice

小結

到這里我們可以一個結論,篩選合適的通知器的總的過程在 AbstractAdvisorAutoProxyCreator#findEligibleAdvisors(..) 方法中進行,分為下面幾步:

  1. 找符合條件的 Advisor 們,在 AbstractAdvisorAutoProxyCreator 則是去找當前 IoC 容器中所有 Advisor 類型的 Bean
  2. 從上一步找到的 Advisor 篩選出能夠應用於當前 Bean 的 Advisor 們,主要是通過 Pointcut 的 ClassFilter 類過濾器和 MethodMatcher 方法匹配器進行判斷,有一個方法匹配這個 Advisor 即滿足條件
  3. 支持對找到的 Advisor 集合進行擴展,在子類中會往其首部添加一個方法攔截器為 ExposeInvocationInterceptor 的 PointcutAdvisor
  4. 對找到的合適的 Advisor 進行排序,排序結果如上所述

上面過程的第 1 步僅找到當前 IoC 容器中所有 Advisor 類型的 Bean,是不是沒有對 AspectJ 相關注解進行解析,這個過程在子類中實現,也就是接下來要講的內容

AnnotationAwareAspectJAutoProxyCreator

org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator:支持從帶有 @AspectJ 注解 Bean 中解析 Advisor 對象

構造函數

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {

	/**
	 * 用於指定哪些 Bean 能夠作為 Advisor
	 */
	@Nullable
	private List<Pattern> includePatterns;
	/**
	 * 解析 AspectJ 注解的 Advisor 工廠
	 */
	@Nullable
	private AspectJAdvisorFactory aspectJAdvisorFactory;
	/**
	 * 構建器模式,用於構建  AspectJ 注解的 Advisor
	 */
	@Nullable
	private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;

	@Override
	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 初始化 BeanFactoryAdvisorRetrievalHelperAdapter
		super.initBeanFactory(beanFactory);
        // 初始化 ReflectiveAspectJAdvisorFactory
		if (this.aspectJAdvisorFactory == null) {
			this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
		}
        // 初始化 BeanFactoryAspectJAdvisorsBuilderAdapter
		this.aspectJAdvisorsBuilder =
				new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
	}
}

2.1.2 findCandidateAdvisors 方法

findCandidateAdvisors(),該方法會去找符合條件的 Advisor 們,通過父類找到當前 IoC 容器中所有 Advisor 類型的 Bean,這里又會解析出帶有 @AspectJ 注解的 Bean 中的 Advisor 們,如下:

protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    // <1> 調用父類方法,從 IoC 容器中查找所有的 Advisor 類型的 Bean
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    // <2> 如果 AspectJ 解析器不為空,默認為 BeanFactoryAspectJAdvisorsBuilderAdapter
    if (this.aspectJAdvisorsBuilder != null) {
        // 解析所有帶有 @AspectJ 注解的 Bean
        // 其中帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解的方法會被解析成一個 PointcutAdvisor 對象
        // 將解析出來的所有 Advisor 添加至 `advisors` 中
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    // <3> 返回 `advisors` 集合(當前 IoC 容器中解析出來的所有的 Advisor 對象)
    return advisors;
}

該方法的處理過程如下:

  1. 調用父類方法,從 IoC 容器中查找所有的 Advisor 類型的 Bean,保存至 advisors 中,可返回上面的 2.1.1 findCandidateAdvisors 方法 小節查看
  2. 如果 AspectJ 解析器不為空,默認為 BeanFactoryAspectJAdvisorsBuilderAdapter,則通過它解析出 Advisor 來
    • 解析所有帶有 @AspectJ 注解的 Bean
    • 其中帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解的方法會被解析成一個 PointcutAdvisor 對象
    • 將解析出來的所有 Advisor 添加至 advisors
  3. 返回 advisors 集合(當前 IoC 容器中解析出來的所有的 Advisor 對象)

BeanFactoryAspectJAdvisorsBuilderAdapter

關於 @AspectJ 注解的解析由 BeanFactoryAspectJAdvisorsBuilderAdapter 完成,如下:

// AnnotationAwareAspectJAutoProxyCreator.java
private class BeanFactoryAspectJAdvisorsBuilderAdapter extends BeanFactoryAspectJAdvisorsBuilder {

    public BeanFactoryAspectJAdvisorsBuilderAdapter(
            ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {

        super(beanFactory, advisorFactory);
    }

    @Override
    protected boolean isEligibleBean(String beanName) {
        return AnnotationAwareAspectJAutoProxyCreator.this.isEligibleAspectBean(beanName);
    }
}

protected boolean isEligibleAspectBean(String beanName) {
    if (this.includePatterns == null) {
        return true;
    } else {
        for (Pattern pattern : this.includePatterns) {
            if (pattern.matcher(beanName).matches()) {
                return true;
            }
        }
        return false;
    }
}

這里只重寫了 isEligibleBean(String) 方法,用於判斷這個 Bean 是否有資格作為一個 Advisor。可以看到是通過 includePatternsbeanName 進行判斷,匹配通過才有資格。當然,includePatterns 一般為空,都有資格。

這個類繼承了 BeanFactoryAspectJAdvisorsBuilder 構建器,我們來看到這個構建器是如何解析的。

BeanFactoryAspectJAdvisorsBuilder

org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder,Advisor 構建器,用於解析出當前 BeanFactory 中所有帶有 @AspectJ 注解的 Bean 中的 Advisor

構造函數

public class BeanFactoryAspectJAdvisorsBuilder {
	/**
	 * 當前 IoC 容器,DefaultListableBeanFactory
	 */
	private final ListableBeanFactory beanFactory;
	/**
	 * Advisor 工廠,用於解析 @AspectJ 注解的 Bean 中的 Advisor
	 */
	private final AspectJAdvisorFactory advisorFactory;
	/**
	 * 用於緩存帶有 @AspectJ 注解的 Bean 的名稱
	 */
	@Nullable
	private volatile List<String> aspectBeanNames;
	/**
	 * 緩存 @AspectJ 注解的單例 Bean 中解析出來的 Advisor
	 * key:帶有 @AspectJ 注解的 beanName
	 * value:其內部解析出來的 Advisor 集合
	 */
	private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<>();
	/**
	 * 緩存 @AspectJ 注解的非單例 Bean 的元數據實例構建工廠
	 * key:帶有 @AspectJ 注解的 beanName(非單例)
	 * value:對應的元數據工廠對象
	 */
	private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache = new ConcurrentHashMap<>();

	public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
		Assert.notNull(beanFactory, "ListableBeanFactory must not be null");
		Assert.notNull(advisorFactory, "AspectJAdvisorFactory must not be null");
		this.beanFactory = beanFactory;
		this.advisorFactory = advisorFactory;
	}
}

2.1.3 buildAspectJAdvisors 方法

buildAspectJAdvisors() 方法,解析出當前 BeanFactory 中所有帶有 @AspectJ 注解的 Bean 中的 Advisor,如下:

public List<Advisor> buildAspectJAdvisors() {
    // <1> 從緩存中獲取所有帶有 @AspectJ 注解的 Bean,保存至 `aspectNames` 集合中
    List<String> aspectNames = this.aspectBeanNames;

    // <2> 緩存中沒有,則對當前對象加鎖再判斷緩存中是否有數據
    if (aspectNames == null) {
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            // <3> 還是沒有緩存,則進行接下來的處理
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();
                aspectNames = new ArrayList<>();
                // <3.1> 獲取當前 IoC 容器中所有的 Bean 的名稱集合
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                // <3.2> 遍歷所有的 Bean 的名稱,進行處理
                for (String beanName : beanNames) {
                    // <3.3> 判斷這個 Bean 是否有資格,默認都為 true
                    if (!isEligibleBean(beanName)) {
                        // 如果沒有資格則跳過
                        continue;
                    }
                    // We must be careful not to instantiate beans eagerly as in this case they
                    // would be cached by the Spring container but would not have been weaved.
                    // <3.4> 獲取這個 Bean 的 Class 對象,如果為空則跳過
                    Class<?> beanType = this.beanFactory.getType(beanName);
                    if (beanType == null) {
                        continue;
                    }
                    // <3.5> 如果這個 Bean 帶有 @Aspect 注解,且沒有以 `ajc$` 開頭的字段,那么進行接下來的解析過程
                    if (this.advisorFactory.isAspect(beanType)) {
                        // <3.5.1>  將這個 Bean 的名稱保存至 `aspectNames` 集合中
                        aspectNames.add(beanName);
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        // <3.5.2> 判斷 @AspectJ 注解的類別是否為 `singleton`,默認空的情況就是這個
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                            MetadataAwareAspectInstanceFactory factory =
                                    new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            // <3.5.2.1> 解析這個 Bean 中帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解的方法
                            // 會解析成對應的 InstantiationModelAwarePointcutAdvisorImpl 對象(PointcutAdvisor)
                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            // <3.5.2.2> 如果這個 Bean 是單例模式,則將解析出來的 Advisor 全部緩存至 `advisorsCache` 中
                            if (this.beanFactory.isSingleton(beanName)) {
                                this.advisorsCache.put(beanName, classAdvisors);
                            }
                            // <3.5.2.3> 否則,將這個 Bean 對應的 MetadataAwareAspectInstanceFactory(AspectJ 元數據實例構建工廠)緩存至 `aspectFactoryCache` 中
                            else {
                                this.aspectFactoryCache.put(beanName, factory);
                            }
                            // <3.5.2.4> 將解析出來的 Advisor 添加至 `advisors` 中
                            advisors.addAll(classAdvisors);
                        }
                        // <3.5.3> 否則,這個 AspectJ 不是單例模式,不能將解析出來的 Advisor 緩存,其他的處理過程都和上面一樣
                        else {
                            // Per target or per this.
                            if (this.beanFactory.isSingleton(beanName)) {
                                throw new IllegalArgumentException("Bean with name '" + beanName +
                                        "' is a singleton, but aspect instantiation model is not singleton");
                            }
                            MetadataAwareAspectInstanceFactory factory =
                                    new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                            // 將這個 Bean 對應的 MetadataAwareAspectInstanceFactory(AspectJ 元數據實例構建工廠)緩存至 `aspectFactoryCache` 中
                            this.aspectFactoryCache.put(beanName, factory);
                            // 解析出這個 Bean 中所有的 Advisor,並添加至 `advisors` 中
                            advisors.addAll(this.advisorFactory.getAdvisors(factory));
                        }
                    }
                }
                // <3.6> 對 `aspectNames` 進行緩存
                this.aspectBeanNames = aspectNames;
                // <3.7> 返回所有 AspectJ 的所有的 Advisor 對象們
                return advisors;
            }
        }
    }

    if (aspectNames.isEmpty()) {
        return Collections.emptyList();
    }
    List<Advisor> advisors = new ArrayList<>();
    /*
     * <4> 否則,遍歷緩存中的 AspectJ 的 beanName
     */
    for (String aspectName : aspectNames) {
        // <4.1> 嘗試從 `advisorsCache` 緩存中獲取這個 beanName 對應的所有 Advisor 們,並添加至 `advisors` 中
        List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
        if (cachedAdvisors != null) {
            advisors.addAll(cachedAdvisors);
        }
        // <4.2> `advisorsCache` 緩存中沒有,
        // 則根據 `aspectFactoryCache` 緩存中對應的 MetadataAwareAspectInstanceFactory(AspectJ 元數據實例構建工廠)解析出所有的 Advisor 們,並添加至 `advisors` 中
        else {
            MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
            advisors.addAll(this.advisorFactory.getAdvisors(factory));
        }
    }
    // <5> 返回所有 AspectJ 的所有的 Advisor 對象們
    return advisors;
}

該方法的處理過程稍微有點復雜,如下:

  1. 從緩存中獲取所有帶有 @AspectJ 注解的 Bean,保存至 aspectNames 集合中
  2. 緩存中沒有,則對當前對象加鎖再判斷緩存中是否有數據
  3. 還是沒有緩存,則進行接下來的處理
    1. 獲取當前 IoC 容器中所有的 Bean 的名稱集合
    2. 遍歷所有的 Bean 的名稱,進行處理
    3. 判斷這個 Bean 是否有資格,默認都為 true
    4. 獲取這個 Bean 的 Class 對象,如果為空則跳過
    5. 如果這個 Bean 帶有 @Aspect 注解,且沒有以 ajc$ 開頭的字段,那么進行接下來的解析過程
      1. 將這個 Bean 的名稱保存至 aspectNames 集合中
      2. 判斷 @AspectJ 注解的類別是否為 singleton,默認空的情況就是這個
        1. 通過 AspectJAdvisorFactory#getAdvisors(..) 方法解析出這個 Bean 中帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解的方法,例如會解析成 InstantiationModelAwarePointcutAdvisorImpl 對象(PointcutAdvisor)
        2. 如果這個 Bean 是單例模式,則將解析出來的 Advisor 全部緩存至 advisorsCache
        3. 否則,將這個 Bean 對應的 MetadataAwareAspectInstanceFactory(AspectJ 元數據實例構建工廠)緩存至 aspectFactoryCache
        4. 將解析出來的 Advisor 添加至 advisors
      3. 否則,這個 AspectJ 不是單例模式,不能將解析出來的 Advisor 緩存,其他的處理過程都和上面一樣
    6. aspectNames 進行緩存
    7. 返回所有 AspectJ 的所有的 Advisor 對象們
  4. 否則,遍歷緩存中的 AspectJ 的 beanName,進行處理
    1. 嘗試從 advisorsCache 緩存中獲取這個 beanName 對應的所有 Advisor 們,並添加至 advisors
    2. advisorsCache 緩存中沒有,則根據 aspectFactoryCache 緩存中對應的 MetadataAwareAspectInstanceFactory(AspectJ 元數據實例構建工廠)解析出所有的 Advisor 們,並添加至 advisors
  5. 返回所有 AspectJ 的所有的 Advisor 對象們

做個小結,整個過程稍微復雜一點,會嘗試從緩存中獲取 Advisor,緩存中沒有數據則先獲取到所有帶有 @AspectJ 注解的 Bean,通過 ReflectiveAspectJAdvisorFactory 對這些 Bean 中帶有 AspectJ 相關注解的方法進行處理,生成對應的 PointcutAdvisor 對象。

接下來,我們來看看 ReflectiveAspectJAdvisorFactory 解析 @AspectJ 注解的 Bean 的過程

ReflectiveAspectJAdvisorFactory

org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory,Advisor 工廠,用於解析 @AspectJ 注解的 Bean 中的 Advisor

構造函數

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
	/**
	 * 方法比較器
	 */
	private static final Comparator<Method> METHOD_COMPARATOR;

	static {
		Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
				new InstanceComparator<>( Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
				(Converter<Method, Annotation>) method -> {
					AspectJAnnotation<?> annotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
					return (annotation != null ? annotation.getAnnotation() : null);
				});
		Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
		METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
	}
}

可以看到有一個 Comparator 方法比較器,順序是 @Around > @Before > @After > @AfterReturning > @AfterThrowing,注意獲取到應用於某個 Bean 的 Advisor 的順序不是這樣子,可以回到前面的 2.4 sortAdvisors 方法 小節看看

2.1.3.1 getAdvisors 方法

getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) 方法,解析出這個 Bean(帶有 @AspectJ 注解)中所有的 Advisor,方法入參是 Bean 的元數據實例構建工廠,方法如下:

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // <1> 獲取這個 Bean 的 Class 對象和 beanName
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    validate(aspectClass);

    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    List<Advisor> advisors = new ArrayList<>();

    /*
     * <2> 遍歷沒有標注 @Pointcut 注解的方法(順序:@Around > @Before > @After > @AfterReturning > @AfterThrowing)
     */
    for (Method method : getAdvisorMethods(aspectClass)) {
        /*
         * <2.1> 如果這個方法帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解
         * 則根據注解信息創建一個 InstantiationModelAwarePointcutAdvisorImpl 對象
         * 這個對象就是 PointcutAdvisor 類型,包含了 Pointcut 和 Advice
         */
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
        // <2.2> 生成了 PointcutAdvisor 則添加至 `advisor` 集合中
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // If it's a per target aspect, emit the dummy instantiating aspect.
    // <3> 如果這個 Aspect 需要延遲初始化,則往首部添加一個 PointcutAdvisor
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        advisors.add(0, instantiationAdvisor);
    }

    // Find introduction fields.
    // <4> 根據帶有 @DeclareParents 注解的字段生成 IntroductionAdvisor 對象,並添加至 `advisor` 集合中
    for (Field field : aspectClass.getDeclaredFields()) {
        Advisor advisor = getDeclareParentsAdvisor(field);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // <5> 返回這個 Aspect 中所有的 Advisor 對象
    return advisors;
}

該方法的處理過程如下:

  1. 獲取這個 Bean 的 Class 對象和 beanName

  2. 遍歷沒有標注 @Pointcut 注解的方法(順序:@Around > @Before > @After > @AfterReturning > @AfterThrowing

    private List<Method> getAdvisorMethods(Class<?> aspectClass) {
       final List<Method> methods = new ArrayList<>();
       ReflectionUtils.doWithMethods(aspectClass, method -> {
          // Exclude pointcuts
          // 排除 @Pointcut 注解標注的方法
          if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
             methods.add(method);
          }
       });
       // 進行排序
       methods.sort(METHOD_COMPARATOR);
       return methods;
    }
    
    1. 調用 getAdvisor(..) 方法,將這個方法解析成 InstantiationModelAwarePointcutAdvisorImpl 對象(PointcutAdvisor),這個方法必須帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解
    2. 如果上一步解析出了 Advisor 對象,則添加至 advisor 集合中
  3. 如果這個 Aspect 需要延遲初始化,則往首部添加一個 SyntheticInstantiationAdvisor(PointcutAdvisor),暫時忽略

  4. 調用 getDeclareParentsAdvisor(..) 方法,根據帶有 @DeclareParents 注解的字段生成 IntroductionAdvisor 對象,並添加至 advisor 集合中

    private Advisor getDeclareParentsAdvisor(Field introductionField) {
        DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
        if (declareParents == null) {
            return null;
        }
        if (DeclareParents.class == declareParents.defaultImpl()) {
            throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
        }
        return new DeclareParentsAdvisor(
                introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
    }
    
  5. 返回這個 Aspect 中所有的 Advisor 對象,也就是返回 advisor 集合

可以看到 @AspectJ 注解的 Bean 中的 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解方法在 getAdvisor(..) 方法中進行

2.1.3.2 getAdvisor 方法

getAdvisor(..) 方法,解析 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解方法,生成 PointcutAdvisor 對象,如下:

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
        int declarationOrderInAspect, String aspectName) {

    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

    /*
     * <1> 嘗試根據該方法生成一個 AspectJExpressionPointcut 對象
     * 根據 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解信息進行創建,沒有的話則返回 null
     */
    AspectJExpressionPointcut expressionPointcut = getPointcut(
            candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    if (expressionPointcut == null) {
        return null;
    }

    /*
     * <2> 如果存在上面其中一個注解,則將創建的 AspectJExpressionPointcut 封裝成 InstantiationModelAwarePointcutAdvisorImpl 對象
     * 也就是封裝成了 PointcutAdvisor 對象,會初始化一個 Advice,也就是注解標注的方法
     * 那么這個對象中就包含了 Pointcut 和 Advice,就可以判斷某個方法是否被攔截,攔截后應該如何處理
     */
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
            this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

該方法的處理過程如下:

  1. 調用 getPointcut(..) 方法,嘗試根據該方法生成一個 AspectJExpressionPointcut 對象,根據 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解信息進行創建,沒有的話則返回 null
  2. 如果存在上面其中一個注解,則將創建的 AspectJExpressionPointcut 封裝成 InstantiationModelAwarePointcutAdvisorImpl 對象,也就是封裝成了 PointcutAdvisor 對象,會初始化一個 Advice,也就是注解標注的方法。那么這個對象中就包含了 Pointcut 和 Advice,就可以判斷某個方法是否被攔截,攔截后應該如何處理

getPointcut 方法

getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) 方法,嘗試將方法解析成 AspectJExpressionPointcut 對象,如下:

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
    // <1> 找到這個方法的 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解信息
    AspectJAnnotation<?> aspectJAnnotation =
            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
        return null;
    }

    // <2> 如果帶有上面其中一個注解,則創建一個 AspectJExpressionPointcut 對象
    AspectJExpressionPointcut ajexp =
            new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
    // <3> 設置 Pointcut 的表達式
    ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
    if (this.beanFactory != null) {
        ajexp.setBeanFactory(this.beanFactory);
    }
    // <4> 返回 AspectJExpressionPointcut 對象
    return ajexp;
}

該方法的處理過程如下:

  1. 找到這個方法的 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解信息
  2. 如果帶有上面其中一個注解,則創建一個 AspectJExpressionPointcut 對象
  3. 設置 Pointcut 的表達式
  4. 返回 AspectJExpressionPointcut 對象

getAdvice 方法

getAdvice(..) 方法,主要根據 AspectJExpressionPointcut 初始化一個 Advice 對象,如下:

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

    Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    validate(candidateAspectClass);

    // 獲取 @Pointcut、@Around、@Before、@After、@AfterReturning、@AfterThrowing 注解
    AspectJAnnotation<?> aspectJAnnotation =
            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
        return null;
    }

    // If we get here, we know we have an AspectJ method.
    // Check that it's an AspectJ-annotated class
    if (!isAspect(candidateAspectClass)) {
        throw new AopConfigException("Advice must be declared inside an aspect type: " +
                "Offending method '" + candidateAdviceMethod + "' in class [" +
                candidateAspectClass.getName() + "]");
    }

    if (logger.isDebugEnabled()) {
        logger.debug("Found AspectJ method: " + candidateAdviceMethod);
    }

    AbstractAspectJAdvice springAdvice;

    switch (aspectJAnnotation.getAnnotationType()) {
        case AtPointcut:
            if (logger.isDebugEnabled()) {
                logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
            }
            return null;
        case AtAround: // @Around -> AspectJAroundAdvice
            springAdvice = new AspectJAroundAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtBefore: // @Before -> AspectJMethodBeforeAdvice
            springAdvice = new AspectJMethodBeforeAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtAfter: // @After -> AspectJAfterAdvice
            springAdvice = new AspectJAfterAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtAfterReturning: // @AfterReturning -> AspectJAfterAdvice
            springAdvice = new AspectJAfterReturningAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                springAdvice.setReturningName(afterReturningAnnotation.returning());
            }
            break;
        case AtAfterThrowing: // @AfterThrowing -> AspectJAfterThrowingAdvice
            springAdvice = new AspectJAfterThrowingAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
            }
            break;
        default:
            throw new UnsupportedOperationException(
                    "Unsupported advice type on method: " + candidateAdviceMethod);
    }

    // Now to configure the advice...
    springAdvice.setAspectName(aspectName);
    springAdvice.setDeclarationOrder(declarationOrder);
    /*
     * 獲取方法的參數名列表
     */
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
        // 設置參數名
        springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    springAdvice.calculateArgumentBindings();

    return springAdvice;
}

根據注解的類型創建對應的 Advice 類型,如下:

  • @Around:AspectJAroundAdvice,實現了 MethodInterceptor
  • @Before:AspectJMethodBeforeAdvice
  • @After:AspectJAfterAdvice,實現了 MethodInterceptor
  • @AfterReturning: AspectJAfterAdvice
  • @AfterThrowing:AspectJAfterThrowingAdvice,實現了 MethodInterceptor

InstantiationModelAwarePointcutAdvisorImpl

org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl,AspectJ 注解方法解析后的對象,實現了 PointcutAdvisor,包含 Pointcut 和 Advice

final class InstantiationModelAwarePointcutAdvisorImpl
		implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {

	private static final Advice EMPTY_ADVICE = new Advice() {};

	private final AspectJExpressionPointcut declaredPointcut;

	private final Class<?> declaringClass;

	private final String methodName;

	private final Class<?>[] parameterTypes;

	private transient Method aspectJAdviceMethod;

	private final AspectJAdvisorFactory aspectJAdvisorFactory;

	private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;

	private final int declarationOrder;

	private final String aspectName;

	private final Pointcut pointcut;

	private final boolean lazy;

	@Nullable
	private Advice instantiatedAdvice;

	@Nullable
	private Boolean isBeforeAdvice;

	@Nullable
	private Boolean isAfterAdvice;

	public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
			Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		// AspectJExpressionPointcut 對象
		this.declaredPointcut = declaredPointcut;
		// Advice 所在的 Class 對象
		this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
		// Advice 對應的方法名稱
		this.methodName = aspectJAdviceMethod.getName();
		// Advice 對應的方法參數類型
		this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
		// Advice 對應的方法對象
		this.aspectJAdviceMethod = aspectJAdviceMethod;
		// Advisor 工廠,用於解析 @AspectJ 注解的 Bean 中的 Advisor
		this.aspectJAdvisorFactory = aspectJAdvisorFactory;
		// 元數據實例構建工廠
		this.aspectInstanceFactory = aspectInstanceFactory;
		// 定義的順序
		this.declarationOrder = declarationOrder;
		// Advice 所在 Bean 的名稱
		this.aspectName = aspectName;

		// 如果需要延遲初始化,則不立即初始化 Advice 對象
		if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			// Static part of the pointcut is a lazy type.
			Pointcut preInstantiationPointcut = Pointcuts.union(
					aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

			// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
			// If it's not a dynamic pointcut, it may be optimized out
			// by the Spring AOP infrastructure after the first evaluation.
			this.pointcut = new PerTargetInstantiationModelPointcut(
					this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
			this.lazy = true;
		}
		// 否則,初始化 Advice 對象
		else {
			// A singleton aspect.
			// AspectJExpressionPointcut 對象
			this.pointcut = this.declaredPointcut;
			this.lazy = false;
			// 根據 AspectJExpressionPointcut 初始化一個 Advice 對象
			// `@Around`:AspectJAroundAdvice,實現了 MethodInterceptor
			// `@Before`:AspectJMethodBeforeAdvice
			// `@After`:AspectJAfterAdvice,實現了 MethodInterceptor
			// `@AfterReturning`: AspectJAfterAdvice
			// `@AfterThrowing`:AspectJAfterThrowingAdvice,實現了 MethodInterceptor
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		}
	}
    
    private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
		Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
				this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
		return (advice != null ? advice : EMPTY_ADVICE);
	}
}

總結

在上一篇《Spring AOP 自動代理(一)入口》文章講述了 Spring AOP 自動代理的入口,主要對 AbstractAutoProxyCreator 這個類進行了分析。本文接着上一篇文章分析了在 Spring AOP 自動代理的的過程中,如何從 Spring 上下文篩選出能夠應用於某個 Bean 的 Advisor 們,大致的流程如下:

  1. 解析出當前 IoC 容器所有 Advisor 對象

    1. 獲取當前 IoC 容器所有 Advisor 類型的 Bean
    2. 解析當前 IoC 容器中所有帶有 @AspectJ 注解的 Bean,將內部帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 注解的方法解析出對應的 PointcutAdvisor 對象,帶有 @DeclareParents 注解的字段解析出 IntroductionAdvisor 對象
  2. 篩選出能夠應用於這個 Bean 的 Advisor 們,主要通過 ClassFilter 類過濾器和 MethodMatcher 方法匹配器進行匹配

  3. 對篩選出來的 Advisor 進行擴展,例如子類會往首部添加一個 PointcutAdvisor 對象

  4. 對篩選出來的 Advisor 進行排序

    • 不同的 AspectJ 根據 @Order 排序

    • 同一個 AspectJ 中不同 Advisor 的排序,優先級:AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice

AspectJ 中的注解對應的 Advice 類型如下:

  • @Around -> AspectJAroundAdvice,實現了 MethodInterceptor
  • @Before -> AspectJMethodBeforeAdvice
  • @After -> AspectJAfterAdvice,實現了 MethodInterceptor
  • @AfterReturning -> AspectJAfterAdvice
  • @AfterThrowing -> AspectJAfterThrowingAdvice,實現了 MethodInterceptor

好了,本篇文章就到這里了,如果獲取到能夠應用於某個 Bean 的 Advisor,那么接下來要做的就是為這個 Bean 創建一個代理對象,通過 JDK 動態代理或者 CGLIB 動態代理,將在下篇文章進行分析。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM