出发点 闲来无事回顾几个项目中的一些内容,把一些重复代码用AOP重新处理了一下,定义切入点时采用了自定义注解的形式,原因是这样最精准、最容易控制,当然缺点是需要手动把注解加到各个方法上去。项目里还有用到声明式事务(@Transactional
)和声明式缓存(@Cacheable
),所以有的方法就会存在3个以上的切面相关注解,注解一多就发现对它们的执行顺序机理的理解有些模糊,遂打算重新理一遍Spring AOP的内容,回顾一把这个经典到不能再经典的工具。为了方便,底子还是用的SpringBoot,顺便也回顾下SpringBoot中事务、AOP等自动配置的相关内容,分析分析源码。本文默认您已经有对Spring AOP与声明式事务管理的基本认知,采用的版本信息:SpringBoot 2.3.3.RELEASE(Spring 5.2.8.RELEASE)
声明式事务原理 首先整理下声明式事务,在SpringBoot环境下不需要单独引入事务相关的依赖或者单独添加启用事务的注解,通常引入相关的持久层依赖就可以直接使用@Transactional
这个注解,而如果要使用Spring AOP您需要显式引入依赖项spring-boot-starter-aop
。声明式事务本质上也是AOP思想的产物,那么为什么没有诸如spring-boot-starter-transaction
,为什么使用声明式事务不需要引入spring-aop是个值得思考的问题。
对于普通Spring项目来说,使用声明式事务需要显式进行指定。xml配置中需要添加标签<tx:annotation-driven>
(使@Transactional
生效)或者使用标签<tx:advice>
来声明事务切入;使用Java config形式则需要在配置类上添加注解@EnableTransactionManage
。而SpringBoot可以不准确的描述为更高级的Java config,我们知道SpringBoot自带的自动配置类都在spring-boot-autoconfigure
包下,很容易找到事务相关的自动配置类org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
:
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 @Configuration(proxyBeanMethods = false) @ConditionalOnClass(PlatformTransactionManager.class) @AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class }) @EnableConfigurationProperties(TransactionProperties.class) public class TransactionAutoConfiguration { @Bean @ConditionalOnMissingBean public TransactionManagerCustomizers platformTransactionManagerCustomizers ( ObjectProvider<PlatformTransactionManagerCustomizer<?>> customizers) { return new TransactionManagerCustomizers (customizers.orderedStream().collect(Collectors.toList())); } @Bean @ConditionalOnMissingBean @ConditionalOnSingleCandidate(ReactiveTransactionManager.class) public TransactionalOperator transactionalOperator (ReactiveTransactionManager transactionManager) { return TransactionalOperator.create(transactionManager); } @Configuration(proxyBeanMethods = false) @ConditionalOnSingleCandidate(PlatformTransactionManager.class) public static class TransactionTemplateConfiguration { @Bean @ConditionalOnMissingBean(TransactionOperations.class) public TransactionTemplate transactionTemplate (PlatformTransactionManager transactionManager) { return new TransactionTemplate (transactionManager); } } @Configuration(proxyBeanMethods = false) @ConditionalOnBean(TransactionManager.class) @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class) public static class EnableTransactionManagementConfiguration { @Configuration(proxyBeanMethods = false) @EnableTransactionManagement(proxyTargetClass = false) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false) public static class JdkDynamicAutoProxyConfiguration { } @Configuration(proxyBeanMethods = false) @EnableTransactionManagement(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) public static class CglibAutoProxyConfiguration { } } }
因此还是回到了@EnableTransactionManagement
这注解上,值得额外注意的一点是当前版本SpringBoot环境下该注解的proxyTargetClass属性默认设置为true(matchIfMissing的作用),这与注解属性本身的默认值(false)不同,也就是说SpringBoot默认采用CGLIB作为动态代理解决方案,有关于这一点的具体可以参考这个issue 的讨论。接下来继续深入该注解:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(TransactionManagementConfigurationSelector.class) public @interface EnableTransactionManagement { boolean proxyTargetClass () default false ; AdviceMode mode () default AdviceMode.PROXY; int order () default Ordered.LOWEST_PRECEDENCE; }
该注解主要的功能就是引入TransactionManagementConfigurationSelector
,其作为接口ImportSelector
的实现类目的是引入一些Configuration配置类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector <EnableTransactionManagement> { @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String [] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String [] {determineTransactionAspectClass()}; default : return null ; } } private String determineTransactionAspectClass () { return (ClassUtils.isPresent("javax.transaction.Transactional" , getClass().getClassLoader()) ? TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME : TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME); } }
以默认的PROXY模式为例(ASPECTJ需要额外引入spring-aspects依赖并执行其他操作),可以看到引入了两个配置类:AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
,这两个类自身代码量都不多,逐个查看源码:
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 80 81 82 83 84 public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar { private final Log logger = LogFactory.getLog(getClass()); @Override public void registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean candidateFound = false ; Set<String> annTypes = importingClassMetadata.getAnnotationTypes(); for (String annType : annTypes) { AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType); if (candidate == null ) { continue ; } Object mode = candidate.get("mode" ); Object proxyTargetClass = candidate.get("proxyTargetClass" ); if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) { candidateFound = true ; if (mode == AdviceMode.PROXY) { AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return ; } } } } if (!candidateFound && logger.isInfoEnabled()) { String name = getClass().getSimpleName(); logger.info(String.format("%s was imported but no annotations were found " + "having both 'mode' and 'proxyTargetClass' attributes of type " + "AdviceMode and boolean respectively. This means that auto proxy " + "creator registration and configuration may not have occurred as " + "intended, and components may not be proxied as expected. Check to " + "ensure that %s has been @Import'ed on the same class where these " + "annotations are declared; otherwise remove the import of %s " + "altogether." , name, name, name)); } } } @Configuration(proxyBeanMethods = false) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor ( TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) { BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor (); advisor.setTransactionAttributeSource(transactionAttributeSource); advisor.setAdvice(transactionInterceptor); if (this .enableTx != null ) { advisor.setOrder(this .enableTx.<Integer>getNumber("order" )); } return advisor; } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource () { return new AnnotationTransactionAttributeSource (); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionInterceptor transactionInterceptor (TransactionAttributeSource transactionAttributeSource) { TransactionInterceptor interceptor = new TransactionInterceptor (); interceptor.setTransactionAttributeSource(transactionAttributeSource); if (this .txManager != null ) { interceptor.setTransactionManager(this .txManager); } return interceptor; } }
ProxyTransactionManagementConfiguration
引入了事务处理的解析、处理和整体描述相关的Bean,那么如何让这些Bean发挥作用,真正应用到方法中就应该是AutoProxyRegistrar
所引入的Bean(严格来说是Bean Definition)要做的事情。沿着关键代码AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)
的调用链一直到最后,可以看到如下代码:
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 @Nullable private static BeanDefinition registerOrEscalateApcAsRequired ( Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null" ); if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null ; } RootBeanDefinition beanDefinition = new RootBeanDefinition (cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order" , Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; } private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList <>(3 );static { APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); }
在没有其他配置的情况下InfrastructureAdvisorAutoProxyCreator
将作为AutoProxyRegistrar
引入的Bean的具体类型,查看它的类图如下:
实现的核心接口为SmartInstaniationAwareBeanPostProcessor
,它的继承结构说明了它是一个修改Bean的钩子,核心的处理逻辑方法是postProcessAfterInitialization
:
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 @Override public Object postProcessAfterInitialization (@Nullable Object bean, String beanName) { if (bean != null ) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this .earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary (Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this .targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this .advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this .advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null ); if (specificInterceptors != DO_NOT_PROXY) { this .advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource (bean)); this .proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this .advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
看到这里基本上就能够明白注解配置的声明式事务是如何生效的了,以PROXY模式为例,总结如下:
使用注解@EnableTransactionManagement
,该注解根据配置的mode属性引入了AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
两个组件。
AutoProxyRegistrar
尝试向容器中添加自动代理生成器(Auto Proxy Creator)的BeanDefinition,采用的实现类为InfrastructureAdvisorAutoProxyCreator
。APC实现了BeanPostProcessor
接口,将在Bean实例化后执行代理的生成操作,PC会尝试从BeanFactory中获取实现了Advisor
接口的Bean来作为代理生成的依据。
ProxyTransactionManagementConfiguration
是一个配置类,它注册了BeanFactoryTransactionAttributeSourceAdvisor
(事务增强Advisor)、TransactionAttributeSource
(事务注解属性解析器)、TransactionInterceptor
(事务执行拦截器)三个组件。
TransactionAttributeSource
的职能是解析@Transactional
注解中的属性值并包装为事务相关属性,TransactionInterceptor
包含了事务的具体执行逻辑。这两个Bean作为BeanFactoryTransactionAttributeSourceAdvisor
的组件由它进行方法调用。
APC将在Bean实例化时根据获取到的事务Advisor判断是否需要生成增强代理,如果Bean的类或方法上包含了@Transactional
注解,那么将生成包含事务拦截器的代理类,完成事务增强。
Spring AOP原理 其实我们都知道声明式事务是AOP的子集,是它的应用之一,但是我们使用AOP需要引入spring-boot-starter-aop,而不引入并不影响我们使用声明式事务。接下来一探究竟Spring AOP是如何生效的。
找到AOP的自动配置类org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
:
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 @Configuration(proxyBeanMethods = false) @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) public class AopAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass(Advice.class) static class AspectJAutoProxyingConfiguration { @Configuration(proxyBeanMethods = false) @EnableAspectJAutoProxy(proxyTargetClass = false) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false) static class JdkDynamicAutoProxyConfiguration { } @Configuration(proxyBeanMethods = false) @EnableAspectJAutoProxy(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) static class CglibAutoProxyConfiguration { } } @Configuration(proxyBeanMethods = false) @ConditionalOnMissingClass("org.aspectj.weaver.Advice") @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) static class ClassProxyingConfiguration { ClassProxyingConfiguration(BeanFactory beanFactory) { if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } } } }
可以看到配置内容和声明式事务非常相似,同样还是以Java Config注解@EnableAspectJAutoProxy
作为入口,也是将注解的proxy-target-class暴露到配置文件中。
1 2 3 4 5 6 7 8 9 10 11 12 13 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { boolean proxyTargetClass () default false ; boolean exposeProxy () default false ; }
还是同样的配方,使用了@Import
注解引入组件,但是数量略有减少,只有一个名为AspectJAutoProxyRegistrar
的工具类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions ( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null ) { if (enableAspectJAutoProxy.getBoolean("proxyTargetClass" )) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy" )) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } }
很明显起作用的还是添加Aspect Proxy Creator相关的Bean Definition,根据上述的优先级AnnotationAwareAspectJAutoProxyCreator
将会覆盖InfrastructureAdvisorAutoProxyCreator
。这几个候选APC的继承关系如下图所示:
对比一下InfrastructureAdvisorAutoProxyCreator
和AspectJAwareAdvisorAutoProxyCreator
这两个同级的类分别覆盖了哪些方法:
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 public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { @Nullable private ConfigurableListableBeanFactory beanFactory; @Override protected void initBeanFactory (ConfigurableListableBeanFactory beanFactory) { super .initBeanFactory(beanFactory); this .beanFactory = beanFactory; } @Override protected boolean isEligibleAdvisorBean (String beanName) { return (this .beanFactory != null && this .beanFactory.containsBeanDefinition(beanName) && this .beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE); } } public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator (); @Override protected List<Advisor> sortAdvisors (List<Advisor> advisors) { List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList <>(advisors.size()); for (Advisor advisor : advisors) { partiallyComparableAdvisors.add( new PartiallyComparableAdvisorHolder (advisor, 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 { return super .sortAdvisors(advisors); } } @Override protected void extendAdvisors (List<Advisor> candidateAdvisors) { AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors); } @Override protected boolean shouldSkip (Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true ; } } return super .shouldSkip(beanClass, beanName); } private static class PartiallyComparableAdvisorHolder implements PartialComparable { } }
可以看到两者并没有进行核心内容上的更改,都是针对各自应用场景的修补,InfrastructureAdvisorAutoProxyCreator
只为框架本身的工具服务,而AspectJAwareAdvisorAutoProxyCreator
添加了一些针对AspectJ声明切面的处理逻辑,所以本质上两者还是保持一致的。AspectJAwareAdvisorAutoProxyCreator
并没有创建Advisor的相关逻辑,而EnableAspectJAutoProxy
只引入这一个工具,可以猜想到根据注解解析Advisor的内容包含在它的子类AnnotationAwareAspectJAutoProxyCreator
中,忽略一些非主要代码展示如下:
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 public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { @Nullable private List<Pattern> includePatterns; @Nullable private AspectJAdvisorFactory aspectJAdvisorFactory; @Nullable private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder; @Override protected void initBeanFactory (ConfigurableListableBeanFactory beanFactory) { super .initBeanFactory(beanFactory); if (this .aspectJAdvisorFactory == null ) { this .aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory (beanFactory); } this .aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter (beanFactory, this .aspectJAdvisorFactory); } @Override protected List<Advisor> findCandidateAdvisors () { List<Advisor> advisors = super .findCandidateAdvisors(); if (this .aspectJAdvisorsBuilder != null ) { advisors.addAll(this .aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; } }
正如这个类的名称AnnotationAwareAspectJAutoProxyCreator
,它添加了对aspectj注解(@Aspect
、@PointCut
、@Before
等等)的支持。Spring AOP生效逻辑总结如下:
使用注解@EnableAspectJAutoProxy
,由它引入AspectJAutoProxyRegistrar
,开启对Java注解声明式AOP的支持
AspectJAutoProxyRegistrar
向容器中添加AnnotationAwareAspectJAutoProxyCreator
作为APC的实现类,它将覆盖其他APC(如果存在)
AnnotationAwareAspectJAutoProxyCreator
除了对实现了Advisor
接口的Bean的处理之外,同时会判断Bean是否包含了aspectj相关的注解,并根据这些注解生成对应的Advisor
APC将在Bean实例化时根据获取到的Advisor判断是否需要生成增强代理
三种候选APC优先级依次提高,分别对应不同的场景:
InfrastructureAdvisorAutoProxyCreator
:对应一些内部框架功能实现的支持,例如声明式事务、声明式缓存等
AspectJAwareAdvisorAutoProxyCreator
:对应XML配置场景下的AOP声明支持(所以它不直接包含对于切面定义的处理)
AnnotationAwareAspectJAutoProxyCreator
:对应Java Config配置场景下注解式AOP声明的支持
切入顺序解析 当业务功能逐步增加,可能会加入各种各样的切面逻辑,这种情况下就需要额外关注切入的顺序,顺序不对可能会造成严重的问题。接下来顺着代码看看Spring AOP对于切面顺序是如何处理的。
经过上面的分析,我们可以从AbstractAutoProxyCreator
的postProcessAfterInitialization方法进入:
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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 @Override public Object postProcessAfterInitialization (@Nullable Object bean, String beanName) { if (bean != null ) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this .earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary (Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this .targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this .advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this .advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null ); if (specificInterceptors != DO_NOT_PROXY) { this .advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource (bean)); this .proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this .advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } @Override @Nullable protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } protected List<Advisor> findEligibleAdvisors (Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; } protected List<Advisor> sortAdvisors (List<Advisor> advisors) { AnnotationAwareOrderComparator.sort(advisors); return advisors; } protected List<Advisor> sortAdvisors (List<Advisor> advisors) { List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList <>(advisors.size()); for (Advisor advisor : advisors) { partiallyComparableAdvisors.add( new PartiallyComparableAdvisorHolder (advisor, 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 { return super .sortAdvisors(advisors); } }
所以不同的切面之间都是使用AnnotationAwareOrderComparator
来确定顺序,该类继承自OrderComparator
,增加了对Spring注解@Order
和J2EE注解@Priority
的支持。它的比较的逻辑可以总结如下:
如果实现了Ordered接口则使用Ordered.getOrder()方法获取排序值
如果没有实现Ordered接口,查找类对象是否有添加两种支持的注解(包括继承关系),如果找到注解则使用注解的属性值作为排序值
如果都没有,排序值取Ordered.LOWEST_PRECEDENCE(2147483647)
如果两者只有一方实现了PriorityOrdered
接口,那么实现方优先级更高,否则根据排序值比较
排序值越大,优先级越低
而对于同一个切面中的advice来说,就需要使用额外的判断,这部分说实话不是特别明白,有兴趣可以深入一下源码,这里就翻译一下AspectJAwareAdvisorAutoProxyCreator#sortAdvisors
方法的javadoc吧:
根据aspectj优先级对提供的advisor实例进行排序。如果两个advice来自同一个advisor,那么它们的顺序是一样的。同一个advisor的advice将使用如下规则进一步排序:如果任意一方是’After’类型的advice,那么后声明的优先级最高(即最后运行),否则先声明的优先级最高(即最先运行)。
这其实也是符合常识逻辑的排序,即先声明的先执行,但是由于切面的结构,在出方向上优先级最高的最后执行,所以最后声明的’After’类型的advice因为优先级最高最后执行。
原始顺序 那么在排序值相同的情况下,不同advice的同类型的advice如何确定顺序呢?我们可以看到执行advice之间排序的AbstractAdvisorAutoProxyCreator.sortAdvisors这个方法最终会使用List.sort(Comparator)来执行排序,查看该方法的javadoc可以得知使用的排序实现是从MergeSort优化而来的TimSort,它是一种稳定排序算法,因此可以推断出如果排序值相同,那么顺序就取决于他们之间原来的顺序。重新追溯回到原始顺序的源头:
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 protected List<Advisor> findEligibleAdvisors (Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; } protected List<Advisor> findCandidateAdvisors () { Assert.state(this .advisorRetrievalHelper != null , "No BeanFactoryAdvisorRetrievalHelper available" ); return this .advisorRetrievalHelper.findAdvisorBeans(); } @Override protected List<Advisor> findCandidateAdvisors () { List<Advisor> advisors = super .findCandidateAdvisors(); if (this .aspectJAdvisorsBuilder != null ) { advisors.addAll(this .aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; } public List<Advisor> findAdvisorBeans () { String[] advisorNames = this .cachedAdvisorBeanNames; if (advisorNames == null ) { 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) { } } } } return advisors; }
由上面的代码可知,Advisor的原始顺序取决于BeanFactory取出相关Bean名称的顺序,同时由注解描述构建出的Advisor全部排在原生Advisor实现类的后面。具体到SpringBoot的应用场景下,最后执行的内容为DefaultListableBeanFactory
下的方法:
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 private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { List<String> result = new ArrayList <>(); for (String beanName : this .beanDefinitionNames) { if (!isAlias(beanName)) { try { RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); if (!mbd.isAbstract() && (allowEagerInit || (mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) && !requiresEagerInitForType(mbd.getFactoryBeanName()))) { if (matchFound) { result.add(beanName); } } } } } for (String beanName : this .manualSingletonNames) { try { if (isTypeMatch(beanName, type)) { result.add(beanName); } } catch (NoSuchBeanDefinitionException ex) { logger.trace(LogMessage.format( "Failed to check manually registered singleton with name '%s'" , beanName), ex); } } return StringUtils.toStringArray(result); }
最终我们可以看到原始数据的顺序来源于BeanFactory的beanDefinitionNames这个List<String>
类型的成员,这个集合包含了所有注册的Bean名称,并且维持了Bean注册的顺序,Bean注册的细节此处就不展开了,我们可以直接在上述方法打断点调试,根据SpringBoot运行调试结果可以看出如下几点规则:
6个内置的Bean和SpringBoot启动类最先注册,内置Bean包括internalConfigurationAnnotationProcessor
,internalAutowiredAnnotationProcessor
,internalCommonAnnotationProcessor
,internalEventListenerProcessor
,internalEventListenerFactory
,internalCachingMetadataReaderFactory
接下来根据扫包获取应用代码中声明的Bean,扫包顺序通常是按照全类名的字母序(包括@Configuration
修饰的配置类,但不包括其中定义的Bean)
然后是应用代码中引入的Bean,包括配置类下声明的Bean以及Import引入的Bean
最后是SpringBoot自动配置类相关的内容
总结 Spring AOP的核心类是AutoProxyCreator,它作为钩子工具在Bean实例化时执行了代理创建操作,这也再一次表明Spring AOP在默认的proxy模式下使用的是动态代理,Spring只是借用了AspectJ的一些切面描述的注解,并没有使用依赖特殊编译器的静态织入。
切面的顺序是一个必须考虑的问题,Spring主要通过org.springframework.core.Ordered
接口以及org.springframework.core.annotation.Order
注解(还包括j2ee的Priority注解)来声明排序值以控制顺序。在SpringBoot应用环境下,您需要额外注意几点:
开启声明式事务的注解@EnableTransactionManagement
包含在自动配置类中,并没有将order属性直接暴露到配置文件中,其默认的顺序值为Ordered.LOWEST_PRECEDENCE
即最低顺序。如果必须要配置,可以手动在应用配置类上主动使用@EnableTransactionManagement
并修改order属性值,但是这会让配置文件中的一些相关配置失效。
同时使用声明式事务和声明式缓存并且不修改order值,由于声明式缓存需要手动添加@EnableCaching
,这使得默认情况下缓存Advisor的原始顺序高于事务Advisor,因此先切面的入口处先执行缓存逻辑再执行事务逻辑,这恰好满足一般的使用常理。
在开启Spring AOP使用aspectj注解声明切面时,如果不指定Order顺序值,那么默认顺序值为最低顺序,根据原始顺序的逻辑,构建出来的切面全部位于原生切面的后面,也就是排在事务等框架提供的逻辑之后,您需要确保这是没问题的,否则请显式指定顺序值。
不同的切面推荐放在不同的类中并指定顺序值,防止意想不到的结果发生。