原始博文链接
出发点
闲来无事回顾几个我的项目中的一些内容,把一些反复代码用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
:
@Configuration(proxyBeanMethods = false)// 依赖PlatformTransactionManager, 该类位于spring-tx包下@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())); } // reactive相干,能够暂不思考 @Bean @ConditionalOnMissingBean @ConditionalOnSingleCandidate(ReactiveTransactionManager.class) public TransactionalOperator transactionalOperator(ReactiveTransactionManager transactionManager) { return TransactionalOperator.create(transactionManager); } // 配置TransactionTemplate @Configuration(proxyBeanMethods = false) @ConditionalOnSingleCandidate(PlatformTransactionManager.class) public static class TransactionTemplateConfiguration { @Bean @ConditionalOnMissingBean(TransactionOperations.class) public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) { return new TransactionTemplate(transactionManager); } } // 事务的次要配置内容,依据应用的代理形式分成两种:jdk proxy和cglib proxy @Configuration(proxyBeanMethods = false) @ConditionalOnBean(TransactionManager.class) // 这个contion意味着你能够被动应用@EnableTransactional,不采纳如下的默认配置 @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class) public static class EnableTransactionManagementConfiguration { @Configuration(proxyBeanMethods = false) // 应用与一般java config雷同的注解 @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的探讨。接下来持续深刻该注解:
@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配置类:
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { // 依据@EnableTransactionManagement注解的mode属性来确定引入的配置类 @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: // 默认应用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
,这两个类本身代码量都不多,一一查看源码:
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) { // 重点在于如下几句代码,尝试注册AutoProxyCreator 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 { // 事务Advisor实现类,援用了前面两个Bean @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; } // 事务属性解析器,应用的是AnnotaionTransactionAtributeSource,用于解析@Transactional注解的属性 @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)
的调用链始终到最初,能够看到如下代码:
// from org.springframework.aop.config.AopConfigUtils// 入参 cls 的类对象为InfrastructureAdvisorAutoProxyCreator@Nullableprivate static BeanDefinition registerOrEscalateApcAsRequired( Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); // 查看是否存在固定名称的BeanDefinition if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); // 如果这个名称的Bean的对象类型与入参不同,则依据优先级来判断是否替换对象类型 // 查看findPriorityForClass办法,能够看到返回的是一个List的下标,这个list的 // 内容是动态写死的,蕴含了三种类型(见下方代码)。所以能够了解为这是一个逐渐降级 // 的逻辑,前面将进一步剖析这三个类型 if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // 不存在则创立BD并注册到BeanFactory RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); // 留神这个Bean的优先级被设为最高 beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition;}/** * Stores the auto proxy creator classes in escalation order. */private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);static { // Set up the escalation list... APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);}
在没有其余配置的状况下InfrastructureAdvisorAutoProxyCreator
将作为AutoProxyRegistrar
引入的Bean的具体类型,查看它的类图如下:
实现的外围接口为SmartInstaniationAwareBeanPostProcessor
,它的继承构造阐明了它是一个批改Bean的钩子,外围的解决逻辑办法是postProcessAfterInitialization
:
// from org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator/** * Create a proxy with the configured interceptors if the bean is * identified as one to proxy by the subclass. * @see #getAdvicesAndAdvisorsForBean */@Overridepublic 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; } // 这一步将从获取BeanFactory中获取匹配的Advisor,包含上述的事务Advisor 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
:
@Configuration(proxyBeanMethods = false)// 引入依赖后主动失效,能够通过配置spring.aop.auto=false来敞开@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)public class AopAutoConfiguration { // 依赖类org.aspectj.weaver.Advice,该类属于包org.aspectj.weaver,并且 // spring-aop依赖该包,因而通常这个配置会失效 @Configuration(proxyBeanMethods = false) @ConditionalOnClass(Advice.class) static class AspectJAutoProxyingConfiguration { @Configuration(proxyBeanMethods = false) // 应用与一般java config雷同的注解 @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 { } } // 当org.aspectj.weaver.Advice不存在,即短少依赖时作为候补配置项 // 通常不会进入这个配置块 @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裸露到配置文件中。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(AspectJAutoProxyRegistrar.class)public @interface EnableAspectJAutoProxy { // 是否采纳CGLIB作为代理实现 boolean proxyTargetClass() default false; // 是否将代理本身裸露到ThreadLocal环境以便在拦截器中可能获取到代理自身 boolean exposeProxy() default false;}
还是同样的配方,应用了@Import
注解引入组件,然而数量略有缩小,只有一个名为AspectJAutoProxyRegistrar
的工具类。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { // 注册Bean Definition @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 注册AutoProxyCreator,这里应用实现类是AnnotationAwareAspectJAutoProxyCreator AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); // 依据注解@EnableAspectJAutoProxy上的参数批改BD 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
这两个同级的类别离笼罩了哪些办法:
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { @Nullable private ConfigurableListableBeanFactory beanFactory; @Override protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.initBeanFactory(beanFactory); this.beanFactory = beanFactory; } // 这个办法最终被org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans // 所应用,即限度只有框架自身的Advisor可能失效 @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(); // 笼罩了Advisor排序办法,实质起因是须要对源自对立个Aspect的Advisor进行进一步排序 // 这排序还挺简单的,利用了偏序排序,具体规定请查看该办法的javadoc @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); } } // 增加一个裸露AspectJ调用(MethodInvocation)的前置Advisor,也是利用ThreadLocal @Override protected void extendAdvisors(List<Advisor> candidateAdvisors) { AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors); } // 作为Aspect自身的Bean不能被代理 @Override protected boolean shouldSkip(Class<?> beanClass, String beanName) { // TODO: Consider optimization by caching the list of the aspect names 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
中,疏忽一些非次要代码展现如下:
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); // 创立advisor factory if (this.aspectJAdvisorFactory == null) { this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory); } // 创立advisor builder this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory); } @Override protected List<Advisor> findCandidateAdvisors() { // 父类逻辑调用 List<Advisor> advisors = super.findCandidateAdvisors(); // 这里将依据aspectj注解解析生成额定的advisor 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办法进入:
// ========= AbstractAutoProxyCreator =========@Overridepublic 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;}// ========= AbstractAdvisorAutoProxyCreator =========@Override@Nullableprotected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { // 持续往下走 List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); // 这里对返回值做了一些解决 if (advisors.isEmpty()) { return DO_NOT_PROXY; // 如果没有,返回null } return advisors.toArray();}protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { // 这一步将获取所有候选的Advisor List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 遍历候选的Advisor筛选出其中与Bean相匹配的 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // 本类中为空办法,AspectJAwareAdvisorAutoProxyCreator对其进行了笼罩 // 增加了一个裸露AOP调用的advisor,这个advisor的order值为PriorityOrdered.HIGHEST_PRECEDENCE + 1 extendAdvisors(eligibleAdvisors); // 对advisor进行排序,进入上面的办法,查看是如何排序的 // 这一步不同的APC会有不同的实现,然而也是属于扩大的关系 if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors;}// AbstractAdvisorAutoProxyCreator的默认实现protected List<Advisor> sortAdvisors(List<Advisor> advisors) { // 外部调用的是List.sort(AnnotationAwareOrderComparator.INSTANCE) AnnotationAwareOrderComparator.sort(advisors); return advisors;}// AspectJAwareAdvisorAutoProxyCreator的笼罩实现protected List<Advisor> sortAdvisors(List<Advisor> advisors) { List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size()); // 这里把所有的advisor都包装成为PartiallyComparableAdvisorHolder // DEFAULT_PRECEDENCE_COMPARATOR 的类型为AspectJPrecedenceComparator // 而这个类型外部同样蕴含了一个AnnotationAwareOrderComparator for (Advisor advisor : advisors) { partiallyComparableAdvisors.add( new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR)); } // 应用偏序排序,偏序排序属于离散数学领域,自己也不是特地分明 // 应用这种排序次要是为了解决同一个切面中申明的advice 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,它是一种稳固排序算法,因而能够推断出如果排序值雷同,那么程序就取决于他们之间原来的程序。从新追溯回到原始程序的源头:
// ========= AbstractAdvisorAutoProxyCreator =========protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { // 这一步获取原始Advisor列表,往里面走 List<Advisor> candidateAdvisors = findCandidateAdvisors(); List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors;}// 该办法被子类AnnotationAwareAspectJAutoProxyCreator重写protected List<Advisor> findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); // 应用工具类来获取,持续往里走 return this.advisorRetrievalHelper.findAdvisorBeans();}// AnnotationAwareAspectJAutoProxyCreator重写的findCandidateAdvisors@Overrideprotected List<Advisor> findCandidateAdvisors() { // 调用父类办法 List<Advisor> advisors = super.findCandidateAdvisors(); // 结构依据注解申明的对应的advisor if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors;}// ========= AbstractAdvisorAutoProxyCreator =========public List<Advisor> findAdvisorBeans() { // 获取所有实现了Advisor接口的Bean名称,同时做了缓存解决 String[] advisorNames = this.cachedAdvisorBeanNames; if (advisorNames == null) { // 获取相干的Bean名称,进入此办法持续走 advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } if (advisorNames.length == 0) { return new ArrayList<>(); } List<Advisor> advisors = new ArrayList<>(); // 依照获取到的Bean名称一一增加到List中 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
下的办法:
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { List<String> result = new ArrayList<>(); // 依据beanDefinitionNames这个list成员进行遍历 for (String beanName : this.beanDefinitionNames) { if (!isAlias(beanName)) { try { RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // Only check bean definition if it is complete. if (!mbd.isAbstract() && (allowEagerInit || (mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) && !requiresEagerInitForType(mbd.getFactoryBeanName()))) { // 省略匹配逻辑校验代码 ... if (matchFound) { result.add(beanName); } } } // 省略异样解决代码 ... } } // 依据manualSingletonNames这个list成员遍历 // 这里次要蕴含一些手动管制、无需解决Bean生命周期的单例,比方SpringBootBanner // 通常Advisor实现类不会呈现在这里 for (String beanName : this.manualSingletonNames) { try { // 省略代码... if (isTypeMatch(beanName, type)) { result.add(beanName); } } catch (NoSuchBeanDefinitionException ex) { // Shouldn't happen - probably a result of circular reference resolution... 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程序值,那么默认程序值为最低程序,依据原始程序的逻辑,构建进去的切面全副位于原生切面的前面,也就是排在事务等框架提供的逻辑之后,您须要确保这是没问题的,否则请显式指定程序值。
- 不同的切面举荐放在不同的类中并指定程序值,避免意想不到的后果产生。