Aop相关注解
- @EnableTransactionManagement
- @EnableAspectJAutoProxy
- @EnableAsync
- ...
从注解切入来看看这些注解都干了什么
@Import注解作用简述
注入的类一般继承ImportSelector或者ImportBeanDefinitionRegistrar接口
- 继承ImportSelector接口:selectImports方法返回的类名会被解析成bean
- 继承ImportBeanDefinitionRegistrar接口:会在解析阶段执行registerBeanDefinitions方法
Spring解析流程可以看我之前写的博文 《Spring之ConfigurationClassPostProcessor解析流程》重点讲解了@Import等注解是如何解析的
@EnableAsync注解
@EnableAsync注解作用
- 注入一个类型为AsyncAnnotationBeanPostProcessor的BeanPostProcessor
@EnableTransactionManagement注解
@EnableTransactionManagement注解作用
- 注入一个类型为InfrastructureAdvisorAutoProxyCreator的BeanPostProcessor
- 注入事务相关的bean
@EnableAspectJAutoProxy
@EnableAspectJAutoProxy注解作用
- 注入一个类型为AnnotationAwareAspectJAutoProxyCreator的bpp
@EnableTransactionManagement和@EnableAspectJAutoProxy注解的渊源
从方法的角度
两个类都是通过AopConfigUtils.registerXXX方法注入一个bpp到spring中
注意点:AopConfigUtils的register方法存在三个优先级,如果spring调用了多次register方法,spring会保留优先级最高的bpp(beanName为org.springframework.aop.config.internalAutoProxyCreator)。比如Spring中同时存在@EnableTransactionManagement和@EnableAspectJAutoProxy注解,但因为@EnableAspectJAutoProxy注解注入的bpp的优先级高于@EnableTransactionManagement注解注入的bpp,所以spring只有一个类型为AnnotationAwareAspectJAutoProxyCreator的bean,而不存在类型为InfrastructureAdvisorAutoProxyCreator的bean
相关源码AopConfigUtils#registerOrEscalateApcAsRequired
从类的的角度
两个bpp都继承AbstractAutoProxyCreator,然而Spring动态代理相关的逻辑都是在这个类中处理的,所有我们可以认为@EnableTransactionManagement和@EnableAspectJAutoProxy注解实现动态代理的逻辑是一样的。
注解实现动态代理的时机
@EnableAsync注解
我们从前文中了解到@EnableAsync注解会注入一个类型为AsyncAnnotationBeanPostProcessor的bpp,我们来查看源码
我们通过类的继承关系,关注其祖父类(AbstractAdvisingBeanPostProcessor)的postProcessAfterInitialization方法
@EnableTransactionManagement和@EnableAspectJAutoProxy注解
通过上文的分析,我们主要查看AbstractAutoProxyCreator的postProcessAfterInitialization方法
通过源码,我们得出以下几个结论
- 几个注解注入的bpp都是通过postProcessAfterInitialization方法进行动态代理
- Spring是通过ProxyFactory这个类完成动态代理的
Spring是如何解决多个bpp对bean进行处理的顺序问题
我们回过头查看@EnableAsync注解注入的bpp的postProcessAfterInitialization方法
从码义上来说,@EnableAsync注解进行AOP动态代理优先级是比较低的,那Spring是怎么处理,让优先级比较低的bpp稍后执行呢?
我们查看源码PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
Spring会对所有的bpp进行排序,然后按顺序加入到列表中,优先级较高的优先加入,优先处理
这里的比较器使用的是AnnotationAwareOrderComparator,这个比较器大致分成以下步骤
- bpp是否继承PriorityOrdered接口,如果都继承PriorityOrdered接口,比较getOrder方法返回的值,值越小,优先级越高
- bpp是否继承Ordered接口,如果都继承Ordered接口,比较getOrder方法返回的值,值越小,优先级越高
- bpp所属class上是否存在@Order注解,如果存在,比较@Order注解设置的值,值越小,优先级越高
- 其他
这里需要注意的是,如果一个bpp继承PriorityOrdered接口,getOrder方法返回的值为100,另外一个bpp继承Ordered接口,getOrder方法返回的值为1,按照第一优先级规则,还是继承PriorityOrdered接口的bpp优先级高
我们查看三个注解相关源码
@EnableAsync注解order默认值是Ordered.LOWEST_PRECEDENCE(Integer.MAX_VALUE)
@EnableTransactionManagement注解order默认值是Ordered.LOWEST_PRECEDENCE(Integer.MAX_VALUE)
@EnableAspectJAutoProxy注解未开启设置
默认的情况下,@EnableAsync和@EnableTransactionManagement注解注入的bpp都继承Ordered接口,并且getOrder方法返回的值都是Ordered.LOWEST_PRECEDENCE(Integer.MAX_VALUE),默认情况下优先级一致,但是@EnableTransactionManagement注解注入bpp的时候,对order值进行了手动设置,保证了如果同时存在@EnableAsync和@EnableTransactionManagement注解的情况下,@EnableTransactionManagement注解注入的bpp进行AOP动态代理,@EnableAsync注解注入的bpp进行增强。如果只存在@EnableAsync注解,则相关bpp进行AOP动态代理
相关源码AopConfigUtils#registerOrEscalateApcAsRequired
这里需要说明一下,虽然@EnableAspectJAutoProxy注解不能指定order值,但是有默认值,默认值也是Ordered.LOWEST_PRECEDENCE(Integer.MAX_VALUE),@EnableTransactionManagement和@EnableAspectJAutoProxy注解从一定程度上来说,这些可以指定的参数是互补的,因为它们进行AOP动态代理的是操作是通过共同父类AbstractAutoProxyCreator完成的
总结
- @EnableTransactionManagement,@EnableAspectJAutoProxy,@EnableAsync注解都有可能产生AOP动态代理
- @EnableTransactionManagement,@EnableAspectJAutoProxy注解注入的bpp,都是依靠AbstractAutoProxyCreator这个类完成动态代理的。如果它们同时存在,Spring中只会存在一个优先级更高的bpp。这两个注解指定的参数是互补的,对于特定需求,可以进行扩展
- 几个注解注入的bpp,都是Spring执行到postProcessAfterInitialization方法阶段,完成AOP动态代理
- Spring通过registerOrEscalateApcAsRequired方法手动修改了@EnableTransactionManagement,@EnableAspectJAutoProxy注入的bpp的order值,所以执行顺序优先于@EnableAsync注入的bpp
- 几个注解都是通过ProxyFactory这个类,以策略模式完成AOP动态代理(我们下一篇文章将重点讲解这个类)