spring 事务的实现方式和原理_Spring事务专题(五)聊聊Spring事务到底是如何实现的(上)...

4f7e52d3d9102a0f6bed91ab42c73c08.png

Spring事务专题(五)聊聊Spring事务到底是如何实现的

前言

本专题大纲:

ff4706ee79fb452c6ab4855848ff98c3.png

本文为本专题倒数第二篇文章。

在上篇文章中我们一起学习了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;

}

需要注意的是,@EnableTransactionManagementproxyTargetClass会影响Spring中所有通过自动代理生成的对象。如果将proxyTargetClass设置为true,那么意味通过@EnableAspectJAutoProxy所生成的代理对象也会使用cglib进行代理。关于@EnableTransactionManagement@EnableAspectJAutoProxy混用时的一些问题等我们在对@EnableTransactionManagement有一定了解后再专门做一个比较,现在我们先来看看这个注解到底在做了什么?

f737b3da720b72f3888c4529b7a47405.png

从上图中可以看出这个注解做的就是向容器中注册了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;
}

InfrastructureAdvisorAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator的优先级是如何定义的呢?我们来看看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分析

继承关系

7e2b3c3a8bd1f3280e3083904e9d3e2f.png

这个类的继承关系还是很简单的,只有一个父类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注解是实现这种「看似异步」(实际上并不是)的监听方式的呢?

4c1012a84d4853e0bd51b68bf362da0c.png

大家按照上面这个调用链可以找到这么一段代码

20bb14fcb280d11a4896295885d13cc8.png

通过上面的代码,我们可以发现最终会调用到TransactionalEventListenerFactorycreateApplicationListener方法,通过这个方法创建一个事件监听器然后添加到容器中,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自身做了什么事情。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值