@EnableAspectJAutoProxy
@EnableAspectJAutoProxy注解可以用来开启AOP,那么就从@EnableAspectJAutoProxy入手学习一下Spring AOP的实现原理。
- @EnableAspectJAutoProxy导入了AspectJAutoProxyRegistrar。
- 定义了proxyTargetClass属性,表示是否使用CGLIB生成代理对象,默认返回false,默认是使用JDK动态代理创建代理对象的。
1 | (ElementType.TYPE) |
AspectJAutoProxyRegistrar
AspectJAutoProxyRegistrar是一个代理注册器,它实现了ImportBeanDefinitionRegistrar接口,ImportBeanDefinitionRegistrar可以向容器中注册bean,AspectJAutoProxyRegistrar实现了它应该是为了向容器中注册bean,那么看一下registerBeanDefinitions方法里面注册了什么。
在registerBeanDefinitions方法中它调用了AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法向容器中注册了自动代理创建器,通过名称可以看出它与AspectJ注解以及代理创建有关。
1 | /** |
注册自动代理创建器
registerAspectJAnnotationAutoProxyCreatorIfNecessary在AopConfigUtils中实现:
- 定义了一个自动代理创建器集合,是一个List,List里面的存储顺序代表了优先级,一共有三种代理创建器
- InfrastructureAdvisorAutoProxyCreator:优先级最低
- AspectJAwareAdvisorAutoProxyCreator:优先级较InfrastructureAdvisorAutoProxyCreator高
- AnnotationAwareAspectJAutoProxyCreator:优先级最高
- Spring AOP默认使用的是AnnotationAwareAspectJAutoProxyCreator类型的创建器,向容器中注册的时候会判断容器中是否已经存在代理创建器:
- 如果已经存在,从容器中取出创建器,判断优先级是否比AnnotationAwareAspectJAutoProxyCreator高,如果低于AnnotationAwareAspectJAutoProxyCreator,则使用AnnotationAwareAspectJAutoProxyCreator进行替换。
- 如果不存在,直接向容器中注册AnnotationAwareAspectJAutoProxyCreator类型的bean即可。
1 | public abstract class AopConfigUtils { |
AbstractAutoProxyCreator
自动代理创建器AbstractAutoProxyCreator用于创建代理对象,Spring AOP使用的是AnnotationAwareAspectJAutoProxyCreator类型的创建器,它是AbstractAutoProxyCreator的子类,继承关系如下:
AnnotationAwareAspectJAutoProxyCreator的主要方法都在AbstractAutoProxyCreator中实现,AbstractAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor,它是Spring的Bean后置处理器,后置处理器有两个比较重要的方法:
postProcessBeforeInstantiation:在bean实例化之前执行的方法,如果有自定义的TargetSource则在这个时候就创建代理对象,可以先不管这里,主要看postProcessAfterInitialization方法。
postProcessAfterInitialization:在bean初始化之后执行的方法,这时候bean已经实例化完毕但是还没有设置属性等信息,调用了wrapIfNecessary方法判断是否有必要生成代理对象,如果不需要创建代理对象直接返回即可,反之需要调用getAdvicesAndAdvisorsForBean获取Advice和Advisor,然后创建代理对象。
1 | public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport |
跳过代理对象创建的判断
跳过代理对象的创建主要通过以下两个方法判断的:
1.调用isInfrastructureClass判断是否是基础类,如果是则跳过代理创建。
2.调用shouldSkip方法判断是否需要跳过创建代理。
isInfrastructureClass
需要注意AOP使用的是AnnotationAwareAspectJAutoProxyCreator作为代理创建器,所以需要先看AnnotationAwareAspectJAutoProxyCreator是否重写了该方法,实际上它确实重写isInfrastructureClass方法,在里面它调用了父类的AbstractAutoProxyCreator的isInfrastructureClass和aspectJAdvisorFactory的isAspect进行判断:
- isInfrastructureClass:如果是Advice、Pointcut、Advisor、AopInfrastructureBean及其子类则跳过创建,这些是Spring的基础类,不需要进行代理。
- isAspect:是否有Aspect注解并且不是通过Ajc编译的类则是一个切面。
总结:如果是Advice、Pointcut、Advisor、AopInfrastructureBean及其子类或者bean是一个切面并且不是通过Ajc编译的则跳过代理创建,并将当前bean的缓存key加入到advisedBeans中(wrapIfNecessary中可以看到)。
1 | public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { |
shouldSkip
AnnotationAwareAspectJAutoProxyCreator中重写的shouldSkip方法具体实现在父类AspectJAwareAdvisorAutoProxyCreator里面,它获取所有候选的Advisor进行遍历,判断Advisor是否是AspectJPointcutAdvisor类型并且当前的bean与advisor的AspectName切面名称一致则跳过代理创建:
1 | public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { |
获取所有的Advice和Advisor
getAdvicesAndAdvisorsForBean方法在AbstractAdvisorAutoProxyCreator中实现,它又调用了findEligibleAdvisors方法获取所有可应用到当前bean的Advisors:
- 调用findCandidateAdvisors获取所有候选的Advisor,需要注意的是虽然AbstractAdvisorAutoProxyCreator类中实现了findCandidateAdvisors,但是向容器中注册代理创建器实际的类型是AnnotationAwareAspectJAutoProxyCreator,它重写了findCandidateAdvisors方法,所以会先进入AnnotationAwareAspectJAutoProxyCreator的findCandidateAdvisors方法,它里面又调用了父类的findCandidateAdvisors,这时候才会进入AbstractAdvisorAutoProxyCreator的方法。
- 从所有候选的Advisor中过滤出可以适用于当前bean的Advisor,findAdvisorsThatCanApply具体实现逻辑在AopUtils中。
1 | public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator { |
findCandidateAdvisors获取所有候选的Advisors
AOP使用的是的AnnotationAwareAspectJAutoProxyCreator类型的创建器,它重写了findCandidateAdvisors方法,方法的处理逻辑如下:
调用了父类的findCandidateAdvisors方法获取候选的Advisors,也就是AbstractAdvisorAutoProxyCreator中实现的findCandidateAdvisors方法,这里的Advisors指的是本身是Advisor类型的bean。
调用了buildAspectJAdvisors方法构建Advisors,具体的实现在BeanFactoryAspectJAdvisorsBuilder中, 这里的Advisors指的是使用了@AspectJ注解定义的切面,Spring会把它包装成Advisor。
1 | /** |
1. findCandidateAdvisors获取候选的Advisors
findCandidateAdvisors方法具体的实现在BeanFactoryAdvisorRetrievalHelper中,它从beanFactory中获取了所有Advisor类型的bean:
1 | public class BeanFactoryAdvisorRetrievalHelper { |
2. buildAspectJAdvisors构建Advisor
buildAspectJAdvisors在BeanFactoryAspectJAdvisorsBuilder中实现,这一步用于查找所有使用@AspectJ注解的bean,并将其包装成Advisor返回:
(1)从容器中获取所有的bean,调用isEligibleBean方法判断bean是否符合要求,如果符合进入下一步
(2)调用isAspect方法判断bean是否是一个切面,如果是进入下一步
(3)判断是否是单例模式
- 如果是,创建BeanFactoryAspectInstanceFactory类型的工厂,调用AspectJAdvisorFactory的getAdvisors方法获取Advisor
- 如果不是单例模式,创建PrototypeAspectInstanceFactory类型的工厂,调用AspectJAdvisorFactory的getAdvisors方法获取Advisor
1 | public class BeanFactoryAspectJAdvisorsBuilder { |
isEligibleBean的判断
BeanFactoryAspectJAdvisorsBuilderAdapter是AnnotationAwareAspectJAutoProxyCreator的内部类,它继承了BeanFactoryAspectJAdvisorsBuilder并重写了isEligibleBean方法:
1 | public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { |
isAspect的判断
前面在讲跳过代理对象的创建时已经看到isAspect的实现逻辑,如果使用了Aspect注解并且不是通过Ajc进行编译的,则判定为切面:
1 | // AbstractAspectJAdvisorFactory |
AspectJAdvisorFactory获取Advisor
AspectJAdvisorFactory是一个Advisor工厂,它的继承关系如下:
AnnotationAwareAspectJAutoProxyCreator在初始化bean工厂的方法中,对AspectJAdvisorFactory进行了判断,则如果为空使用ReflectiveAspectJAdvisorFactory:
1 | public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { |
ReflectiveAspectJAdvisorFactory中实现了getAdvisor方法:
- getAdvisorMethods获取Advisor方法(也就是获取通知),具体是根据方法上是否有Pointcut注解来判断的,如果没有Pointcut注解则判定为是Advisor方法
- 调用getAdvisor方法将第1步中获取到的Advisor方法构建为Advisor对象
1 | public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable { |
构建Advisor的具体实现
ReflectiveAspectJAdvisorFactory的getAdvisor方法用于将方法封装为Advisor对象,可以看到第一个参数叫candidateAdviceMethod(候选的通知方法),上一步中传入的是获取到的Advisor方法,所以Spring中Advisor方法指的就是使用了通知注解的方法,getAdvisor方法主要做了如下操作:
- 构建AspectJExpressionPointcut切点表达式对象
- 从通知方法上获取切面相关注解,具体是通过判断方法上是否有Pointcut、Around、Before、After、AfterReturning、AfterThrowing注解实现的
- 从切面注解中获取设置的切点表达式,用于之后判断方法是否匹配使用,然后创建AspectJExpressionPointcut对象并设置获取到的切点表达式
- 将当前的Advisor方法、AspectJExpressionPointcut对象等信息封装为InstantiationModelAwarePointcutAdvisorImpl返回,它是一个Advisor
1 | public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable { |
InstantiationModelAwarePointcutAdvisorImpl封装切面
InstantiationModelAwarePointcutAdvisorImpl是一个Adviosr,它对Aspect切面进行了封装,里面引用了Advice、Pointcut等切面相关信息,在构造函数的最后,调用了instantiateAdvice对通知进行增强处理,也就是根据不同的通知类型,将其包装为不同的Advice对象,具体的实现在ReflectiveAspectJAdvisorFactory中:
1 | final class InstantiationModelAwarePointcutAdvisorImpl |
ReflectiveAspectJAdvisorFactory
ReflectiveAspectJAdvisorFactory中的getAdvice方法中可以看到对通知进行了判断,不同的通知使用不同的包装类:
- 环绕通知,使用AspectJAroundAdvice
- 前置通知,使用AspectJMethodBeforeAdvice
- 后置通知,使用AspectJAfterAdvice
- 返回通知,使用AspectJAfterReturningAdvice
- 异常通知,使用AspectJAfterThrowingAdvice
1 |
|
findAdvisorsThatCanApply获取可以应用到当前bean的Advisor
上一节中获取到了所有的Advisor,接下来要过滤出可以应用到当前bean的Advisor,findAdvisorsThatCanApply在AopUtils中实现:
1 | public abstract class AopUtils { |
核心的逻辑在canApply方法中:
根据切点Pointcut的getClassFilter方法对类进行匹配,判断targetClass目标类是否与切点匹配
从切点获取MethodMatcher方法匹配器,通过MethodMatcher对目标类中的每一个方法进行匹配,也就是使用切点表达式对方法进行匹配,判断方法是否需要拦截。
1 | public abstract class AopUtils { |
创建代理对象
上一节中已经获取到了可以应用到当前bean的Advisor,接下来就可以创建代理对象了,由于篇幅原因,创建代理的过程将另起一篇文章。
总结
参考
Spring版本:5.2.5.RELEASE