Spring源码-Aspect-源码-01

总结摘要
Spring AOP Aspect 源码01

关键方法列表

  1. 解析 AOP 配置
    1. Spring 扩展点InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法。
    2. org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#postProcessBeforeInstantiation
    3. org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
  2. 根据 AOP 配置包装 bean
    1. Spring 扩展点InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法。
    2. org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInitialization
    3. org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

解析 AOP 配置

AbstractAutoProxyCreator#postProcessBeforeInstantiation

源码摘录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);

    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}

流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#postProcessBeforeInstantiation 继承父类 postProcessBeforeInstantiation 方法。
// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation

--> 构建缓存 key
    --|> org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getCacheKey
    --> if 存在 beanName 且为 FactoryBean返回`BeanFactory.FACTORY_BEAN_PREFIX + beanName`。
    --> else-if 存在 beanName返回 beanName
    --> else 返回 beanClass
--> 如果 beanName 为空或缓存`AbstractAutoProxyCreator#targetSourcedBeans`中不存在 key
    --> 如果缓存`AbstractAutoProxyCreator#advisedBeans`中已经解析 bean 解析结果则退出方法
--> 匹配`isInfrastructureClass(beanClass)`条件的 bean 不需要 AOP 代理退出方法
    --|> org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#isInfrastructureClass
    --|> 功能1Advice, Advisor, Pointcut, AopInfrastructureBean 类型的 Bean 满足条件 isInfrastructureClass不需要被代理
        --|> 底层调用 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#isInfrastructureClass
    --|> 功能2注解 @Aspect 修饰且非 ajc 编译的 bean 满足条件 isAspect进而满足条件 isInfrastructureClass不需要被代理
        --|> 底层调用 org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
--> 匹配`shouldSkip(beanClass, beanName)`条件的 bean 不需要 AOP 代理
    --|> org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip
    --> 获取所有的 Advisor
        --|> org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
        --|> 详情参见分支 findCandidateAdvisors
    --> 如果当前 bean 实现了 AspectJPointcutAdvisor则跳过
        --|> 目前未看到 AspectJPointcutAdvisor 使用场景当前的 advisor 均为 InstantiationModelAwarePointcutAdvisorImpl并未继承 AspectJPointcutAdvisor
        --|>  Advisor 类型的 bean在之前步骤`isInfrastructureClass`中已经过滤了应当不会执行到这里
    --> 判断是否是`OriginalInstance`, bean name 后缀为 .ORIGINAL”,则跳过
        --|> org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#shouldSkip
        --> org.springframework.aop.framework.autoproxy.AutoProxyUtils#isOriginalInstance
--> 如果存在用户自定义的创建代理逻辑 customTargetSourceCreators则使用该工具创建代理默认无

AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors

源码摘录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    if (this.aspectJAdvisorsBuilder != null) {
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
    Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
    return this.advisorRetrievalHelper.findAdvisorBeans();
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
public List<Advisor> findAdvisorBeans() {
    // Determine list of advisor bean names, if not cached already.
    String[] advisorNames = this.cachedAdvisorBeanNames;
    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!
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this.beanFactory, Advisor.class, true, false);
        this.cachedAdvisorBeanNames = advisorNames;
    }
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    List<Advisor> advisors = new ArrayList<>();
    for (String name : advisorNames) {
        if (isEligibleBean(name)) {
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Skipping currently created advisor '" + name + "'");
                }
            }
            else {
                try {
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {
                    Throwable rootCause = ex.getMostSpecificCause();
                    if (rootCause instanceof BeanCurrentlyInCreationException) {
                        BeanCreationException bce = (BeanCreationException) rootCause;
                        String bceBeanName = bce.getBeanName();
                        if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                            if (logger.isTraceEnabled()) {
                                logger.trace("Skipping advisor '" + name +
                                        "' with dependency on currently created bean: " + ex.getMessage());
                            }
                            // Ignore: indicates a reference back to the bean we're trying to advise.
                            // We want to find advisors other than the currently created bean itself.
                            continue;
                        }
                    }
                    throw ex;
                }
            }
        }
    }
    return advisors;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
public List<Advisor> buildAspectJAdvisors() {
    List<String> aspectNames = this.aspectBeanNames;

    if (aspectNames == null) {
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();
                aspectNames = new ArrayList<>();
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                for (String beanName : beanNames) {
                    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.
                    Class<?> beanType = this.beanFactory.getType(beanName, false);
                    if (beanType == null) {
                        continue;
                    }
                    if (this.advisorFactory.isAspect(beanType)) {
                        aspectNames.add(beanName);
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                            MetadataAwareAspectInstanceFactory factory =
                                    new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            if (this.beanFactory.isSingleton(beanName)) {
                                this.advisorsCache.put(beanName, classAdvisors);
                            }
                            else {
                                this.aspectFactoryCache.put(beanName, factory);
                            }
                            advisors.addAll(classAdvisors);
                        }
                        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);
                            this.aspectFactoryCache.put(beanName, factory);
                            advisors.addAll(this.advisorFactory.getAdvisors(factory));
                        }
                    }
                }
                this.aspectBeanNames = aspectNames;
                return advisors;
            }
        }
    }

    if (aspectNames.isEmpty()) {
        return Collections.emptyList();
    }
    List<Advisor> advisors = new ArrayList<>();
    for (String aspectName : aspectNames) {
        List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
        if (cachedAdvisors != null) {
            advisors.addAll(cachedAdvisors);
        }
        else {
            MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
            advisors.addAll(this.advisorFactory.getAdvisors(factory));
        }
    }
    return advisors;
}

流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors

-->  beanFactory 中获取所有的 Advisor bean
    --|> org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
    -->  beanFactory 中获取所有的 Advisor bean
        --|> this.advisorRetrievalHelper.findAdvisorBeans();
        --|> org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
        --> 如果缓存`BeanFactoryAdvisorRetrievalHelper#cachedAdvisorBeanNames`不为空表示已经完成查询可以则直接使用缓存从第2次查询起可以使用缓存
        --> 第1次查询时不存在缓存需构建 bean name 缓存
            -->  beanFactory 及祖先 beanFactory 中找到所有`Advisor`类型的 bean name存储到缓存中
                --|> BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);
                --|> org.springframework.beans.factory.BeanFactoryUtils#beanNamesForTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class, boolean, boolean)
        --> 遍历上一步骤获取的 bean name如果满足`isEligibleBean`条件则创建 advisor bean
            --> 匹配条件
                --|> isEligibleBean(name)
                --|> org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.BeanFactoryAdvisorRetrievalHelperAdapter#isEligibleBean
                --> AbstractAdvisorAutoProxyCreator.this.isEligibleAdvisorBean(beanName);
                    --|> org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#isEligibleAdvisorBean
                    --|> 始终返回 true
                    --|> return true;
            --> 创建 bean
                --|> this.beanFactory.getBean(name, Advisor.class)
                --|> org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String, java.lang.Class<T>)
--> 构建 Advisor即获取所有 Spring AOP 配置的切面 Bean
    --|> this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
    --|> org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
    --> 如果缓存`BeanFactoryAspectJAdvisorsBuilder#aspectBeanNames`为空需构建 bean name 缓存第1次查询时不存在缓存
        -->  beanFactory 及祖先 beanFactory 中查询所有的对象方式是找到所有`Object`类型的 bean name
            --|> BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
            --|> org.springframework.beans.factory.BeanFactoryUtils#beanNamesForTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class<?>, boolean, boolean)
        --> 遍历上一步骤获取的 bean name如果满足`isEligibleBean`条件且是 AOP 切面 bean则创建并缓存 advisor
            --> 匹配条件`isEligibleBean(beanName)`,默认始终为 true不满足条件则跳过
                --|> org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.BeanFactoryAspectJAdvisorsBuilderAdapter#isEligibleBean
                    --> org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#isEligibleAspectBean
                    --|> 包含与`<aop:include>`配置相关的匹配条件
                    --|> 当前使用 Spring 注解配置未进行 XML 配置因此满足 isEligibleBean 条件
            --> 获取 beanType如果无法获取则跳过部分 FactoryBean 场景下无法获取
            --> 匹配条件`this.advisorFactory.isAspect(beanType)`,即是否是 AOP 切面不满足条件则跳过
                --|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
                --> 判断 bean 是否被注解`@Aspect`修饰且非 ajc 编译
                    --|> 原因是使用AspectJ语言 Spring AOP编写的切面在通过 ajc 编译得到时也会存在`@Aspect`注解但其并非 Spring 期望的注解方式
                    --> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#hasAspectAnnotation
                        --> AnnotationUtils.findAnnotation(clazz, Aspect.class) != null
                    --> !compiledByAjc(clazz)
            --> 如果切面 bean  AjType 特性Aspect 注解的 value 值配置是单例封装为`BeanFactoryAspectInstanceFactory`。
                --|> 调用`advisorFactory#getAdvisors` 构造 Advisor
                    --|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
                --|> 如果 bean 是单例则存储到缓存`BeanFactoryAspectJAdvisorsBuilder#advisorsCache`,否则存储到缓存`BeanFactoryAspectJAdvisorsBuilder#aspectFactoryCache`。
            --> 如果切面 bean  AjType 特性非单例 bean 也必须是非单例的否则抛出异常
                --|> 封装为`PrototypeAspectInstanceFactory`,存储到缓存`BeanFactoryAspectJAdvisorsBuilder#aspectFactoryCache`。
                --|> 调用`advisorFactory#getAdvisors`构造 Advisor
        --> 返回所有的 advisor
    --> 如果缓存`BeanFactoryAspectJAdvisorsBuilder#aspectBeanNames`不为空则基于缓存获取或创建 advisor从第2次查询起可以使用缓存
        --> 遍历缓存中的 aspectNames
            --> 如果存在于缓存 BeanFactoryAspectJAdvisorsBuilder#advisorsCache 则直接使用缓存中的 advisor
                --|> 表示单例 advisor
            --> 如果存在于缓存 BeanFactoryAspectJAdvisorsBuilder#aspectFactoryCache 则调用 advisorFactory#getAdvisors 构造 advisor
                --|> 表示非单例 advisor
        --> 返回所有的 advisor

此处的 advisor 有

  1. org.springframework.transaction.config.internalTransactionAdvisor注解驱动事务相关的 AOP。

AbstractAdvisorAutoProxyCreator.this.isEligibleAdvisorBean(beanName);有3种实现

  1. org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#isEligibleAdvisorBean
    1. 始终返回 true。
    2. 启用注解驱动的 Spring AOP 后的默认实现。即已注册 AnnotationAwareAspectJAutoProxyCreator
    3. Advisor 查询条件最宽松,可以获取所有 advisor。
  2. org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator#isEligibleAdvisorBean
    1. 校验 bean 的 role 为BeanDefinition.ROLE_INFRASTRUCTURE
    2. 当未启用注解驱动的 Spring AOP,仅支持 Spring 内置的 AOP 场景。即未注册 AnnotationAwareAspectJAutoProxyCreator,而是注册InfrastructureAdvisorAutoProxyCreator时。例如仅启用了注解驱动事务。
  3. org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator#isEligibleAdvisorBean
    1. 校验 bean name 前缀。
    2. 特殊工具类。

AbstractAspectJAdvisorFactory#isAspect 扩展知识

org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect

We consider something to be an AspectJ aspect suitable for use by the Spring AOP system if it has the @Aspect annotation, and was not compiled by ajc. The reason for this latter test is that aspects written in the code-style (AspectJ language) also have the annotation present when compiled by ajc with the -1.5 flag, yet they cannot be consumed by Spring AOP.

我们认为一个对象是适合由Spring AOP系统使用的AspectJ切面,如果它具有@Aspect注解,并且不是由ajc(AspectJ编译器)编译的。进行后者的检查的原因是,使用AspectJ语言(代码风格)编写的切面在通过ajc编译时(使用-1.5标志),也会存在@Aspect注解,但它们无法被Spring AOP使用。

org.aspectj.internal.lang.reflect.AjTypeImpl#getPerClause

org.aspectj.lang.annotation.Aspect 是 AspectJ 提供的注解,用于定义切面(Aspect)。它的 value 属性用于指定切面的实例化模式(即切面的生命周期),默认是单例(singleton),但也可以通过特定语法配置其他作用域。

可选值

说明示例
<font style="color:rgb(85, 85, 85);">""</font>
(空字符串)
默认值,表示切面是单例(Singleton)模式,整个应用共享同一个实例。<font style="color:rgb(85, 85, 85);">@Aspect("")</font>
<font style="color:rgb(85, 85, 85);">@Aspect</font>
<font style="color:rgb(85, 85, 85);">"perthis(...)"</font>为每个匹配切点的目标对象(this)创建一个切面实例。<font style="color:rgb(85, 85, 85);">@Aspect("perthis(execution(* com.example.Service.*(..)))")</font>
<font style="color:rgb(85, 85, 85);">"pertarget(...)"</font>为每个匹配切点的被代理对象(target)创建一个切面实例。<font style="color:rgb(85, 85, 85);">@Aspect("pertarget(execution(* com.example.Dao.*(..)))")</font>
<font style="color:rgb(85, 85, 85);">"percflow(...)"</font>为每个控制流(例如方法调用栈)创建一个切面实例。<font style="color:rgb(85, 85, 85);">@Aspect("percflow(execution(* com.example.Controller.*(..)))")</font>
<font style="color:rgb(85, 85, 85);">"percflowbelow(...)"</font>为每个控制流及子控制流创建一个切面实例。<font style="color:rgb(85, 85, 85);">@Aspect("percflowbelow(execution(* com.example.Service.*(..)))")</font>

ReflectiveAspectJAdvisorFactory#getAdvisors

源码摘录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    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<>();
    for (Method method : getAdvisorMethods(aspectClass)) {
        // Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
        // to getAdvisor(...) to represent the "current position" in the declared methods list.
        // However, since Java 7 the "current position" is not valid since the JDK no longer
        // returns declared methods in the order in which they are declared in the source code.
        // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
        // discovered via reflection in order to support reliable advice ordering across JVM launches.
        // Specifically, a value of 0 aligns with the default value used in
        // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // If it's a per target aspect, emit the dummy instantiating aspect.
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        advisors.add(0, instantiationAdvisor);
    }

    // Find introduction fields.
    for (Field field : aspectClass.getDeclaredFields()) {
        Advisor advisor = getDeclareParentsAdvisor(field);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    return advisors;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory
// 工厂,可以根据遵循 AspectJ 注解语法的 AspectJ 类,通过反射调用相应的通知方法,从而创建 Spring AOP 通知器。
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {

	// Exclude @Pointcut methods
	private static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS
			.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));

	private static final Comparator<Method> adviceMethodComparator;

	static {
		// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
		// an @After advice method will actually be invoked after @AfterReturning and
		// @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
		// invokes proceed() in a `try` block and only invokes the @After advice method
		// in a corresponding `finally` block.
		Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
				new InstanceComparator<>(
						Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
				(Converter<Method, Annotation>) method -> {
					AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
					return (ann != null ? ann.getAnnotation() : null);
				});
		Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
		adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
	}
}

流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
--> 获取切面 bean  class
--> 获取切面 bean  beanName
--> 校验切面 bean  class
    --|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#validate
    --> Aspect 注解校验等忽略
    --> Spring AOP 不支持 `ajType.getPerClause().getKind()``PerClauseKind.PERCFLOW``PerClauseKind.PERCFLOWBELOW`。
--> 懒加载包装器new LazySingletonAspectInstanceFactoryDecorator
--> 获取切面 bean  class 中所有的切面方法并根据指定规则排序
    --|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisorMethods
    --> 筛选条件用户自定义方法且方法未被注解`@Pointcut`修饰(“Exclude @Pointcut methods”)。
        --|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#adviceMethodFilter
        --> 注意此处可能包含无效的切面方法即切面类中未被任何切面相关注解修饰的方法
    --> 排序规则首先注解顺序递增 Around.classBefore.classAfter.classAfterReturning.classAfterThrowing.class其次方法名称顺序
        --|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#adviceMethodComparator
--> for-each 遍历切面方法构建 advisor
    --> 构建 advisor
        --|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor
        --> 校验切面 bean  class
            --|> 在前面步骤中已经进行校验
            --|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#validate
        --> 构建`Pointcut`,封装为`AspectJExpressionPointcut`。
            --|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getPointcut
            --> 获取方法上的 AspectJ 注解只取第一个找到的注解预期方法仅被一个注解修饰),查询顺序为 Pointcut.classAround.classBefore.classAfter.classAfterReturning.classAfterThrowing.class
                --|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#findAspectJAnnotationOnMethod
                --> 注意因为在获取 AspectJ 方法时已经排除了注解 @Pointcut因此此处该注解无效
            --> 封装为`AspectJExpressionPointcut`。`new AspectJExpressionPointcut`。
            --> 配置 AspectJExpressionPointcut 的表达式beanFactory
        --> 如果方法是无效的 AspectJ 方法则返回 null并在上层方法中被忽略
        --> 封装为`InstantiationModelAwarePointcutAdvisorImpl`。
            --|> `new InstantiationModelAwarePointcutAdvisorImpl`
            --|> org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#InstantiationModelAwarePointcutAdvisorImpl
            --> 如果具有 lazy 属性包括 PerClauseKind.PERTHISPerClauseKind.PERTARGETPerClauseKind.PERTYPEWITHIN),进行相关适配并结束方法
            --> else 即如果是单例类),实例化 advice
                --|> org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice
                    --> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
--> 如果 AspectJ bean 具有 lazy 属性则添加`SyntheticInstantiationAdvisor` 作为第一个 advisor
    --|> Synthetic advisor that instantiates the aspect. Triggered by per-clause pointcut on non-singleton aspect. The advice has no effect.
    --|> 合成通知器用于实例化切面当非单例切面上的每个子句切入点被触发时激活该通知没有实际效果
--> 获取 AspectJ bean 中的所有字段
    --|> java.lang.Class#getDeclaredFields
    --|> This includes public, protected, default (package) access, and private fields, but excludes inherited fields.
    --|> 这包括公共受保护默认包级访问和私有字段但不包括继承的字段
--> for-each fields 遍历所有字段构造引入接口字段
    --|> org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getDeclareParentsAdvisor
    --> 如果字段未被注解`@DeclareParents`修饰则忽略该注解修饰1个接口注解属性标识接口的默认实现类
    --> 封装为`DeclareParentsAdvisor`。`new DeclareParentsAdvisor`。
        --|> org.springframework.aop.aspectj.DeclareParentsAdvisor#DeclareParentsAdvisor(java.lang.Class<?>, java.lang.String, java.lang.Class<?>)
            --> `new DelegatePerTargetObjectIntroductionInterceptor(defaultImpl, interfaceType))`
                --> 以反射调用无参构造方法的方式创建 defaultImpl
                    --|> createNewDelegate();

引入通知示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Aspect
public class IntroductionAspect {
    @DeclareParents(value = "tech.gdev.springbasicexplore.aop.springaop.AspectAction+",
            defaultImpl = IntroductionServiceImpl.class)
    public IntroductionService introductionService;
}

public interface IntroductionService {
    void service();
}

public class IntroductionServiceImpl implements IntroductionService {
    @Override
    public void service() {
        System.out.println("[SpringAOP][IntroductionAdvice] IntroductionServiceImpl#service");
    }
}

public class AspectExplore {
    public static void main(String[] args) throws InterruptedException {
        // ...
        
        // 验证引入通知
        AspectAction aspectAction = applicationContext.getBean(AspectAction.class);
        if (aspectAction instanceof IntroductionService) {
            ((IntroductionService) aspectAction).service();
        } else {
            System.out.println("not a IntroductionService");
        }
    }
}

ReflectiveAspectJAdvisorFactory#getAdvice

源码摘录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

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

    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:
            springAdvice = new AspectJAroundAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtBefore:
            springAdvice = new AspectJMethodBeforeAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtAfter:
            springAdvice = new AspectJAfterAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtAfterReturning:
            springAdvice = new AspectJAfterReturningAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                springAdvice.setReturningName(afterReturningAnnotation.returning());
            }
            break;
        case AtAfterThrowing:
            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;
}

流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
--> 获取切面 bean  class
--> 校验切面 bean  class在前面步骤中已经进行校验
    --|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#validate
--> 获取方法上的 AspectJ 注解只取第一个找到的注解预期方法仅被一个注解修饰)。
    --|> 查询顺序为 Pointcut.classAround.classBefore.classAfter.classAfterReturning.classAfterThrowing.class
    --|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#findAspectJAnnotationOnMethod
--> 如果方法是无效的 AspectJ 方法则返回 null并在上层方法中被忽略
--> 如果非 Spring AOP 切面则抛出异常
    --|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
    --|> 在之前步骤中已进行过校验,`org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors`
--> 解析方法上的 AspectJ 注解封装为 Advice
    --|> switch (aspectJAnnotation.getAnnotationType())
    --> case AtPointcut: null忽略 Pointcut 注解
    --> case AtAround: new AspectJAroundAdvice
    --> case AtBefore: new AspectJMethodBeforeAdvice
    --> case AtAfter: new AspectJAfterAdvice
    --> case AtAfterReturning: new AspectJAfterReturningAdvice
    --> case AtAfterThrowing: new AspectJAfterThrowingAdvice
--> 配置属性包括切面 bean name定义顺序等
--> 获取切面方法的切面注解属性`argNames`。
    --|> org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.AspectJAnnotationParameterNameDiscoverer#getParameterNames(java.lang.reflect.Method)
    --|> When compiling without debug info, or when interpreting pointcuts at runtime, the names of any arguments used in the advice declaration are not available. 
    --|> Under these circumstances only, it is necessary to provide the arg names in the annotation - these MUST duplicate the names used in the annotated method. Format is a simple comma-separated list.
    --|> 在不带调试信息编译或者在运行时解释切入点时通知声明中使用的任何参数名称是不可用的
    --|> 在这种情况下必须在注解中提供参数名称——这些名称必须与注解方法中使用的名称一致格式是一个简单的逗号分隔列表
    --> for-each 遍历 argNamestrim 后校验是否 Java 标识符规范
    --> 如果切面的方法声明的参数数量大于 argNames表示使用了内置参数`JoinPoint``ProceedingJoinPoint``JoinPoint.StaticPart`,进行相关适配
--> 如果`argNames`不为空绑定相关参数
    --|> org.springframework.aop.aspectj.AbstractAspectJAdvice#setArgumentNamesFromStringArray
--> 绑定参数通过形参名称映射)。
    --|> org.springframework.aop.aspectj.AbstractAspectJAdvice#calculateArgumentBindings
    --> 首先尝试绑定第1个参数如果其是内置参数`JoinPoint``ProceedingJoinPoint``JoinPoint.StaticPart`。
    --> 通过形参名称映射绑定非内置参数
        --|> org.springframework.aop.aspectj.AbstractAspectJAdvice#bindArgumentsByName
        --> 待补充

切面方法入参示例

前置通知/后置通知的内置参数是org.aspectj.lang.JoinPoint;环绕通知的内置参数是org.aspectj.lang.ProceedingJoinPoint;被切入点的参数信息都被封装到JoinPointProceedingJoinPoint中。除此之外,允许声明通过切入点表达式(如args()@annotation()等)显式绑定的参数。

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Before("execution(* com.example.service.*.*(..)) && args(name)")
public void logBefore(JoinPoint joinPoint, String name) {
    System.out.println("Method: " + joinPoint.getSignature().getName());
    System.out.println("Argument: " + name);
}

@Before("@annotation(logExec)")
public void logBefore(JoinPoint jp, LogExec logExec) {
    // 这里可以拿到注解的全部属性
    System.out.println("[@Before] 方法=" + jp.getSignature().getName()
                     + " | 注解value=" + logExec.value());
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExec {
    String value() default "";   // 随便定义一个属性,演示用
}

END