死磕Spring之AOP篇 – Spring AOP自动代理(二)筛选合适的通知器

死磕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 动态代理,将在下篇文章进行分析。

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 死磕Spring之AOP篇 – Spring AOP自动代理(二)筛选合适的通知器