前言
本专题大纲:
本文为本专题倒数第二篇文章。
在上篇文章中我们一起学习了Spring中的事务抽象机制以及动手模拟了一下Spring中的事务管理机制,那么本文我们就通过源码来分析一下Spring中的事务管理到底是如何实现的,本文将选用Spring5.2.x版本。
从@EnableTransactionManagement开始
Spring事务管理的入口就是@EnableTransactionManagement注解,所以我们直接从这个注解入手,其源码如下:
public @interface EnableTransactionManagement { // 是否使用cglib代理,默认是jdk代理 boolean proxyTargetClass() default false; // 使用哪种代理模式,Spring AOP还是AspectJ AdviceMode mode() default AdviceMode.PROXY; // 为了完成事务管理,会向容器中添加通知 // 这个order属性代表了通知的执行优先级 // 默认是最低优先级 int order() default Ordered.LOWEST_PRECEDENCE; }
需要注意的是,@EnableTransactionManagement的proxyTargetClass会影响Spring中所有通过自动代理生成的对象。如果将proxyTargetClass设置为true,那么意味通过@EnableAspectJAutoProxy所生成的代理对象也会使用cglib进行代理。关于@EnableTransactionManagement跟@EnableAspectJAutoProxy混用时的一些问题等我们在对@EnableTransactionManagement有一定了解后再专门做一个比较,现在我们先来看看这个注解到底在做了什么?
从上图中可以看出这个注解做的就是向容器中注册了AutoProxyRegistrar跟一个ProxyTransactionManagementConfiguration(这里就不考虑AspectJ了,我们平常都是使用SpringAOP),
AutoProxyRegistrar用于开启自动代理,其源码如下:
AutoProxyRegistrar分析
这个类实现了ImportBeanDefinitionRegistrar,它的作用是向容器中注册别的BeanDefinition,我们直接关注它的registerBeanDefinitions方法即可
// AnnotationMetadata,代表的是AutoProxyRegistrar的导入类的元信息 // 既包含了类元信息,也包含了注解元信息 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean candidateFound = false; // 获取@EnableTransactionManagement所在配置类上的注解元信息 Set<String> annTypes = importingClassMetadata.getAnnotationTypes(); // 遍历注解 for (String annType : annTypes) { // 可以理解为将注解中的属性转换成一个map AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType); if (candidate == null) { continue; } // 直接从map中获取对应的属性 Object mode = candidate.get("mode"); Object proxyTargetClass = candidate.get("proxyTargetClass"); // mode,代理模型,一般都是SpringAOP // proxyTargetClass,是否使用cglib代理 if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) { // 注解中存在这两个属性,并且属性类型符合要求,表示找到了合适的注解 candidateFound = true; // 实际上会往容器中注册一个InfrastructureAdvisorAutoProxyCreator if (mode == AdviceMode.PROXY) { AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } // ...... }
@EnableTransactionManagement跟@EnableAspectJAutoProxy
如果对AOP比较了解的话,那么应该知道@EnableAspectJAutoProxy注解也向容器中注册了一个能实现自动代理的bd,那么当@EnableAspectJAutoProxy跟@EnableTransactionManagement同时使用会有什么问题吗?答案大家肯定知道,不会有问题,那么为什么呢?我们查看源码会发现,@EnableAspectJAutoProxy最终调用的是
AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary,其源码如下
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); }
@EnableTransactionManagement最终调用的是,AopConfigUtils#registerAutoProxyCreatorIfNecessary,其源码如下
public static BeanDefinition registerAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source); }
它们最终都会调用registerOrEscalateApcAsRequired方法,只不过传入的参数不一样而已,一个是AnnotationAwareAspectJAutoProxyCreator,另一个是InfrastructureAdvisorAutoProxyCreator。
registerOrEscalateApcAsRequired源码如下:
private static BeanDefinition registerOrEscalateApcAsRequired( Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { // 当前已经注册到容器中的Bean的优先级 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); // 当前准备注册到容器中的Bean的优先级 int requiredPriority = findPriorityForClass(cls); // 谁的优先级大就注册谁,AnnotationAwareAspectJAutoProxyCreator是最大的 // 所以AnnotationAwareAspectJAutoProxyCreator会覆盖别的Bean if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // 注册bd 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; }
InfrastructureAdvisorAutoProxyCreator跟AnnotationAwareAspectJAutoProxyCreator的优先级是如何定义的呢?我们来看看AopConfigUtils这个类中的一个静态代码块
static { APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); }
实际上它们的优先级就是在APC_PRIORITY_LIST这个集合中的下标,下标越大优先级越高,所以AnnotationAwareAspectJAutoProxyCreator的优先级最高,所以AnnotationAwareAspectJAutoProxyCreator会覆盖InfrastructureAdvisorAutoProxyCreator,那么这种覆盖会不会造成问题呢?答案肯定是不会的,因为你用了这么久了也没出过问题嘛~那么再思考一个问题,为什么不会出现问题呢?这是因为InfrastructureAdvisorAutoProxyCreator只会使用容器内部定义的Advisor,但是AnnotationAwareAspectJAutoProxyCreator会使用所有实现了Advisor接口的通知,也就是说AnnotationAwareAspectJAutoProxyCreator的作用范围大于InfrastructureAdvisorAutoProxyCreator,因此这种覆盖是没有问题的。限于篇幅原因这个问题我不做详细解答了,有兴趣的同学可以看下两个类的源码。
@EnableTransactionManagement除了注册了一个AutoProxyRegistrar外,还向容器中注册了一个ProxyTransactionManagementConfiguration。
那么这个ProxyTransactionManagementConfiguration有什么作用呢?
如果大家对我文章的风格有一些了解的话就会知道,分析一个类一般有两个切入点
1.它的继承关系
2.它提供的API
大家自己在阅读源码时也可以参考这种思路,分析一个类的继承关系可以让我们了解它从抽象到实现的过程,即使不去细看API也能知道它的大体作用。仅仅知道它的大致作用是不够的,为了更好了解它的细节我们就需要进一步去探索它的具体实现,也就是它提供的API。这算是我看了这么就源码的一点心得,正好想到了所以在这里分享下,之后会专门写一篇源码心得的文章
ProxyTransactionManagementConfiguration分析
继承关系
这个类的继承关系还是很简单的,只有一个父类
AbstractTransactionManagementConfiguration
AbstractTransactionManagementConfiguration
源码如下:
@Configuration public abstract class AbstractTransactionManagementConfiguration implements ImportAware { @Nullable protected AnnotationAttributes enableTx; @Nullable protected TransactionManager txManager; // 这个方法就是获取@EnableTransactionManagement的属性 // importMetadata:就是@EnableTransactionManagement这个注解所在类的元信息 @Override public void setImportMetadata(AnnotationMetadata importMetadata) { // 将EnableTransactionManagement注解中的属性对存入到map中 // AnnotationAttributes实际上就是个map this.enableTx = AnnotationAttributes.fromMap( importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false)); // 这里可以看到,限定了导入的注解必须使用@EnableTransactionManagement if (this.enableTx == null) { throw new IllegalArgumentException( "@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName()); } } // 我们可以配置TransactionManagementConfigurer // 通过TransactionManagementConfigurer向容器中注册一个事务管理器 // 一般不会这么使用,更多的是通过@Bean的方式直接注册 @Autowired(required = false) void setConfigurers(Collection<TransactionManagementConfigurer> configurers) { // ..... TransactionManagementConfigurer configurer = configurers.iterator().next(); this.txManager = configurer.annotationDrivenTransactionManager(); } // 向容器中注册一个TransactionalEventListenerFactory // 这个类用于处理@TransactionalEventListener注解 // 可以实现对事件的监听,并且在事务的特定阶段对事件进行处理 @Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public static TransactionalEventListenerFactory transactionalEventListenerFactory() { return new TransactionalEventListenerFactory(); } }
TransactionalEventListenerFactory
上面的代码中大家可能比较不熟悉的就是TransactionalEventListenerFactory,这个类主要是用来处理@TransactionalEventListener注解的,我们来看一个实际使用的例子
@Component public class DmzListener { // 添加一个监听器 // phase = TransactionPhase.AFTER_COMMIT意味着这个方法在事务提交后执行 @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) public void listen(DmzTransactionEvent transactionEvent){ System.out.println("事务已提交"); } } // 定义一个事件 public class DmzTransactionEvent extends ApplicationEvent { public DmzTransactionEvent(Object source) { super(source); } } @Component public class DmzService { @Autowired ApplicationContext applicationContext; // 一个需要进行事务管理的方法 @Transactional public void invokeWithTransaction() { // 发布一事件 applicationContext.publishEvent(new DmzTransactionEvent(this)); // 以一条sout语句提代sql执行过程 System.out.println("sql invoked"); } } // 测试方法 public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class); DmzService dmzService = ac.getBean(DmzService.class); dmzService.invokeWithTransaction(); } } // 最后程序会按顺序输出 // sql invoked // 事务已提交
通过上面的例子我们可以看到,虽然我们在invokeWithTransaction方法中一开始就发布了一个事件,但是监听事件的方法却是在invokeWithTransaction才执行的,正常事件的监听是同步的,假设我们将上述例子中的@TransactionalEventListener注解替换成为@EventListener注解,如下:
@Component public class DmzListener { // 添加一个监听器 @EventListener public void listen(DmzTransactionEvent transactionEvent){ System.out.println("事务已提交"); } }
这个时候程序的输出就会是
// 事务已提交 // sql invoked
那么@TransactionalEventListener注解是实现这种看似异步(实际上并不是)的监听方式的呢?
大家按照上面这个调用链可以找到这么一段代码
通过上面的代码,我们可以发现最终会调用到TransactionalEventListenerFactory的createApplicationListener方法,通过这个方法创建一个事件监听器然后添加到容器中,createApplicationListener方法源码如下:
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) { return new ApplicationListenerMethodTransactionalAdapter(beanName, type, method); }
就是创建了一个ApplicationListenerMethodTransactionalAdapter,这个类本身就是一个事件监听器(实现了ApplicationListener接口)。我们直接关注它的事件监听方法,也就是onApplicationEvent方法,其源码如下:
@Override public void onApplicationEvent(ApplicationEvent event) { // 激活了同步,并且真实存在事务 if (TransactionSynchronizationManager.isSynchronizationActive() && TransactionSynchronizationManager.isActualTransactionActive()) { // 实际上是依赖事务的同步机制实现的事件监听 TransactionSynchronization transactionSynchronization = createTransactionSynchronization(event); TransactionSynchronizationManager.registerSynchronization(transactionSynchronization); } // 在没有开启事务的情况下是否处理事件 else if (this.annotation.fallbackExecution()) { // .... // 如果注解中的fallbackExecution为true,意味着没有事务开启的话 // 也会执行监听逻辑 processEvent(event); } else { // .... } }
到这一步逻辑已经清楚了,@TransactionalEventListener所标注的方法在容器启动时被解析成了一个ApplicationListenerMethodTransactionalAdapter,这个类本身就是一个事件监听器,当容器中的组件发布了一个事件后,如果事件匹配,会进入它的onApplicationEvent方法,这个方法并没有直接执行我们所定义的监听逻辑,而是给当前事务注册了一个同步的行为,当事务到达某一个阶段时,这个行为会被触发。通过这种方式,实现一种伪异步。实际上注册到事务的的同步就是TransactionSynchronizationEventAdapter,这个类的源码非常简单,这里就单独取它一个方法看下
// 这个方法会在事务提交前执行 public void beforeCommit(boolean readOnly) { // 在执行时会先判断在@TransactionalEventListener注解中定义的phase是不是BEFORE_COMMIT // 如果不是的话,什么事情都不做 if (this.phase == TransactionPhase.BEFORE_COMMIT) { processEvent(); } }
别看上面这么多内容,到目前为止我们还是只对ProxyTransactionManagementConfiguration的父类做了介绍,接下来我们就来看看ProxyTransactionManagementConfiguration自身做了什么事情。