二刷AOP源码(中)

简介: 二刷AOP源码(中)
public List<Advisor> buildAspectJAdvisors() {
synchronized (this) {
    (1)
     String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                            this.beanFactory, Object.class, true, false);
    (2)
                    for (String beanName : beanNames) {
          (3)
          if (this.advisorFactory.isAspect(beanType)) {
              MetadataAwareAspectInstanceFactory factory =
                                                    new PrototypeAspectInstanceFactory(this.beanFactory, beanName);         
              (4)
              advisors.addAll(this.advisorFactory.getAdvisors(factory));
          }
    (5)
     this.aspectBeanNames = aspectNames;
                    return advisors;
     }
}
}


构建过程分析:

  1. 找到容器所有的BeanDefinition
  2. 遍历这些BeanDefinition
  3. 判断他是不是isAspect类: 此步(AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);查看其是不是被Aspect标注
  4. 从此Aspect类中把所有的建议者提取出来,注册成Bean
  5. 标配缓存(spring 很多工具类都注重缓存的使用

建议者识别提取过程最重要的就在第4步中,我们再深入看看这一步到底干了什么。

这一步是由ReflectiveAspectJAdvisorFactory完成的

Aspect类中识别建议者并注册Bean


public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
        for (Method method : getAdvisorMethods(aspectClass)【1】) {
            Advisor advisor = 【2】getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
            if (advisor != null) {
                advisors.add(advisor);
            }
        }
        // Find introduction fields.
        for (Field field : aspectClass.getDeclaredFields()【3】) {
            Advisor advisor = 【4】getDeclareParentsAdvisor(field);
            if (advisor != null) {
                advisors.add(advisor);
            }
        }
        return advisors;
}

流程:


  1. 先获取被Aspect注解的类中,所有的可能是建议者的方法:getAdvisorMethods获取的是不被Pointcut注解注释的方法,这些都可能是建议者方法,(包含父类,接口方法)
  2. 遍历这些方法:getAdvisor尝试解析这些方法是不是建议者,通过查看其是否被以下注解标注来判断。
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
            Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

是的话,解析注解上的切点信息[列如:上文例子中@Before("webLog()")注解里的weblog()所代表的切点] . 连同本方法信息包装成一个InstantiationModelAwarePointcutAdvisorImpl建议者。

此时


  • 本方法内容是建议内容,方法会包装为AspectJMethodBeforeAdvice建议
  • webLog()切点
  • InstantiationModelAwarePointcutAdvisorImpl 就是建议者
  1. 获取被@DeclareParents注解的属性:这里也可以配置建议者。不同于Before之类的注解标注的方法的是对存在方法的增强。 此种增强叫做引介增强,一个Java类,没有实现A接口,在不修改Java类的情况下,使其具备A接口的功能.这就是引介增强


4.为配置的引介增强创建一个建议者:DeclareParentsAdvisor

此时@Aspect注解的类里配置的建议都被解析出来,并创建了建议者

  • @Aspect注解的类:可以配置多个建议者
  • @Aspect注解的类:可以配置两种增强,普通增强与引介增强


(3.事务建议者

我们再来看看事务建议者是如何被找到的呢?

启动事务注解EnableTransactionManagement 会注册一个ProxyTransactionManagementConfiguration配置类

public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        advisor.setTransactionAttributeSource(transactionAttributeSource());
        advisor.setAdvice(transactionInterceptor());
        advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
        return advisor;
    }
  ....
}

此配置类,直接注册一个建议者:

BeanFactoryTransactionAttributeSourceAdvisor

此建议者:以TransactionInterceptor为建议,以TransactionAttributeSourcePointcut为切点。


我们的@Transactional注解在目标方法扮演的角色是标记,谁的标记?切点的标记,

我们回顾下切点的意义:表示对哪些进行增强,具体表现在其matches方法上,来匹配范围


public boolean matches(Method method, Class<?> targetClass) {
        if (TransactionalProxy.class.isAssignableFrom(targetClass)) {
            return false;
        }
        TransactionAttributeSource tas = getTransactionAttributeSource();
        return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

TransactionAttributeSourcePointcut切点的TransactionAttributeSource的getTransactionAttribute方法,会计算目标方法是否符合被增强的条件,其中决定性的是否被@Transactional标记


到此两种建议者的获取过程,我们已经知晓。有了建议者,接下来就是给目标方法创建创建代理,采纳这些建议。这里涉及到两个问题:

  1. 在什么时机创建代理?
  2. 如何创建代理?


2.2.3.代理的创建时机


这一块涉及到Bean的生命周期。

代理的创建时机肯定是有了目标对象后,才会创建代理啊。目标对象都没有,建议者又是建议的谁呢?


AbstractAdvisorAutoProxyCreator

在Bean创建的生命周期最后一步,即初始化完成后,会走一遍BeanPostProcessor.postProcessAfterInitialization方法,再执行一次扩展。此时Bean已成型。

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        ......
    ......
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }

其中BeanPostProcessor的抽象类AbstractAdvisorAutoProxyCreator会根据是否存在给当前目标对象的建议者,来决定是否创建代理对象。


这块意思很清晰,一个Bean创建出现后,判断是是否有给他提建议的人,有将创建个代理。

2020-5-20修正:说到代理的创建时机,其实有另一种情况。Bean在创建过程中,会尽早暴露一个封装了Bean早期引用的ObjectFactory到第三级缓存,调用ObjectFactory.getObject() 会对Bean执行扩展逻辑。

  • 当不存在循环引用时,第三缓存中的逻辑不会被执行,Bean创建完成后将其从第三缓存移除。
  • 但是当出现循环依赖时,这个第三缓存中的逻辑会被执行 在获取此Bean时会提前执行 Bean的代理创建过程,但同时此Bean并没有走过生命周期。

所以准确的说,创建的代理时机是在目标对象引用创建后。这个之后可能是属性赋值之前;也可能是Bean赋值属性,执行完初始化方法之后.


创建代理的时机就在此处


相关文章
|
2月前
|
Java 数据库连接 应用服务中间件
Spring5源码(39)-Aop事物管理简介及编程式事物实现
Spring5源码(39)-Aop事物管理简介及编程式事物实现
33 0
|
2月前
|
Java Spring
Spring 源码阅读 72:基于 CGLIB 的 AOP 代理的原理(2)- 拦截器的查找与执行
【1月更文挑战第7天】本文分析了基于 CGLIB 的 AOP 代理如何查找和执行拦截器链,其主要的逻辑在 DynamicAdvisedInterceptor 的intercept方法执行。
44 1
|
17天前
|
监控 Java Spring
自定义注解+AOP切面日志+源码
自定义注解+AOP切面日志+源码
19 1
|
27天前
|
Java Spring
【JavaEE进阶】 Spring AOP源码简单剖析
【JavaEE进阶】 Spring AOP源码简单剖析
|
2月前
|
Java Spring
Spring 源码阅读 71:基于 CGLIB 的 AOP 代理的原理(1)- DynamicAdvisedInterceptor 分析
【1月更文挑战第6天】本文分析了基于 CGLIB 的 AOP 代理对象,是通过一个 DynamicAdvisedInterceptor 类型的 Callback 来完成 AOP 增强逻辑处理的,DynamicAdvisedInterceptor 通过实现 MethodInterceptor 接口的intercept方法来处理 AOP 增强逻辑。下一篇,将重点分析这个方法的原理。
69 7
|
2月前
Spring5源码(31)-基于@AspectJ的AOP
Spring5源码(31)-基于@AspectJ的AOP
29 0
|
2月前
|
Java Spring
Spring5源码(30)-基于Schema的AOP
Spring5源码(30)-基于Schema的AOP
26 0
|
2月前
|
Java Spring
Spring5源码(28)-Aop知识点回顾以及基于Advice接口的增强实现
Spring5源码(28)-Aop知识点回顾以及基于Advice接口的增强实现
34 0
|
2月前
|
Java Spring
【Spring源码】Spring中的AOP底层原理分析
【Spring源码】Spring中的AOP底层原理分析
|
11月前
|
Java Spring