Spring源码系列-Spring事务

目录

声明式事务

事务传播行为

源码解析

开启事务

调用顺序

@EnableTransactionManagement注解的两个作用

引入AutoProxyRegistrar后置处理器

引入ProxyTransactionManagerConfiguration配置类

加载切面

事务的Advisor的注册

事务Advice

事务PointCut

创建动态代理

调用代理方法


声明式事务

  • Spring事务,是通过数据库连接来实现的,当前线程中保存了一个map:key是数据源、value是数据库连接
  • 我们说的同一个事务,其实指的是同一个数据库连接,只有拥有同一个数据库连接才能同时提交和回滚
  • 如果在不同的线程,拿到的数据库连接肯定是不一样的,那么肯定也就是不同的事务,所以不要在事务中开启另外的线程去处理业务逻辑,这样会导致业务失效

Spring的事务和Spring AOP原理是差不多的,唯一的不同是,Spring AOP的增强逻辑需要我们程序员自己手动的定义各种Advice,但是spring事务的增强逻辑是spring自己内置提前写好的

事务传播行为

Spring源码系列-Spring事务_第1张图片

Spring源码系列-Spring事务_第2张图片

此时,第28行会更新失败,而第30行因为在父事务的内部又创建了一个子事务,所以第30行会更新成功

  • 一般情况下,第36行的方法需要另起一个类,否则spring不会帮我们重新创建一个新事务(也就是不会重新帮我们执行增强逻辑,在spring事务场景下,执行增强逻辑就是创建新事务)
  • 但是,在当前情况下,为什么没有另起一个类依然创建好了一个新的事务,这是因为第30行,AopContext.currentProxy()拿到了暴露在当前线程中的已经包含了增强逻辑的动态代理对象

这是因为JDK动态代理,默认情况下,调用本类的另外的方法,不会重复的执行增强逻辑,不会重复的执行增强逻辑意味着不会重复的创建新的事务

Spring源码系列-Spring事务_第3张图片

想使用AopContext.currentProxy(),这里就必须开启红框中的配置

不激活aop的注解,也能使用声明式事务,但是就无法暴露动态代理对象,也就无法通过AopContext的形式,显示拿到当前类的动态代理对象了

源码解析

开启事务

Spring源码系列-Spring事务_第4张图片

将MainConfig注册进AnnotatedConfigApplicationContext成为一个配置类,效果等价于给它加上@Configuration注解 

Spring源码系列-Spring事务_第5张图片

AbstractApplicationContext#refresh()中invokeBeanFactoryPostProcessor()中开始解析配置类的时候,就会去解析@Import注解,因为invokeBeanFactoryPostProcessor()内部会调用ConfigurationClassPostProcessor,ConfigurationClassPostProcessor回去解析配置类,而@Import注解就在配置类头上

Spring源码系列-Spring事务_第6张图片

默认就是PROXY,动态代理的方式

调用顺序

AbstractApplicationContext#refresh() ->invokeBeanFactoryPostProcessor() ->ConfigurationClassPostProcessor

ConfigurationClassPostProcessor解析配置类时,会去解析@Import注解,解析实现了ImportBeanDefinitionRegistrar接口的类,将实现了ImportBeanDefinitionRegistrar接口的类放入Map

Spring源码系列-Spring事务_第7张图片

AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,所以AutoProxyRegistrar也会在Map中,所以这里,也会调起AutoProxyRegistrar#registerBeanDefinitions()中,也就是会调起下面的方法

Spring源码系列-Spring事务_第8张图片

AutoProxyRegistrar#registerBeanDefinitions()中,就会通过传进来的BeanDefinitionRegistry来向ioc容器中注册进一些BeanPostProcessor从而实现一些spring事务相关的功能

@EnableTransactionManagement注解的两个作用

引入AutoProxyRegistrar后置处理器

  • 解析切面
  • 创建动态代理

引入ProxyTransactionManagerConfiguration配置类

往IOC容器中事务相关的功能Bean,比如引入事务相关的增强Advisor

Spring源码系列-Spring事务_第9张图片

Spring源码系列-Spring事务_第10张图片

Spring源码系列-Spring事务_第11张图片

Spring源码系列-Spring事务_第12张图片

AutoProxyRegistrar#registerBeanDefinitions()中,就会通过传进来的BeanDefinitionRegistry来向ioc容器中注册InfrustructureAdvisorAutoProxyCreator这个BeanPostProcessor

Spring源码系列-Spring事务_第13张图片

Spring源码系列-Spring事务_第14张图片

注册事务的和注册AOP的后置处理器,使用的是同一个方法,并且在ioc容器中使用的名字都是一样的

Spring源码系列-Spring事务_第15张图片

比较aop的后置处理器和事务的后置处理器哪个优先级高,aop的后置处理器优先级更高,所以就会调用第129行,把beanClass给覆盖掉(因为事务的后置处理器先被执行进入ioc)

事务和AOP注解同时开启时,AOP的后置处理器,会覆盖掉事务的后置处理器

Spring源码系列-Spring事务_第16张图片

Spring源码系列-Spring事务_第17张图片

优先级,aop的后置处理器更高

后置处理器注册好后

Spring源码系列-Spring事务_第18张图片

Spring源码系列-Spring事务_第19张图片

就会在bean被实例化、属性注入、初始化后,来到

Spring源码系列-Spring事务_第20张图片

加载切面

AOP时,就是要在这里解析切面类,解析成为一个个的Advisor

事务时,当然也是要将创建事务的增强逻辑,解析成为一个Advisor

Spring源码系列-Spring事务_第21张图片

Spring源码系列-Spring事务_第22张图片

Spring源码系列-Spring事务_第23张图片

Spring源码系列-Spring事务_第24张图片

事务的Advisor的注册

ProxyTransactionManagerConfiguration这个也就是一个配置类,配置类中会通过@Bean引入很多实现事务功能的相关Bean,当前ProxyTransactionManagerConfiguration就是自动引入了事务的Advisor

  • 可以看到使用SpringBoot时,每引入一个小功能都有一个自己专属的Configuration配置类,每个专属配置类中都有自己相关的功能Bean,
  • 比如引入Redis时,就有Redis专属的配置类RedisAutoConfiguration
  • 比如引入Spring事务时,就有事务专属的ProxyTransactionManagerConfiguration配置类

Spring源码系列-Spring事务_第25张图片

Spring源码系列-Spring事务_第26张图片

Spring源码系列-Spring事务_第27张图片

事务Advice

Spring源码系列-Spring事务_第28张图片

后续调用下面的动态代理的pay()方法时,就会来上上面的invoke()方法来做一些事务方面的增强工作

Spring源码系列-Spring事务_第29张图片

事务PointCut

Spring源码系列-Spring事务_第30张图片

因为事务没有使用像aop的切点表达式来进行匹配,而是使用了@Transactional注解来做的匹配,只要你方法头上有@Transactional注解,那么就给你执行事务Advice中的增强逻辑创建新事务

TransactionAttributeSource,就是去扫描解析类的那些方法头上有@Transactional注解

  • 事务的Advisor是spring自己提供了,并自己注册进ioc容器的,
  • AOP的Advisor是需要项目启动时,直接解析出来的

事务aop和普通aop的不同点是

1. 普通aop的那些增强逻辑,都是用户通过@Before,@After等注解来自定义的。这些自定义的增强逻辑,需要spring通过后置处理器如解析它们,把它们解析成一个个得Advisor。

事务的增强逻辑是内置的,也就是spring自己写的。所以Spring就自己给我们写好了一个事务专有的Advisor,并注册到了ioc容器中。

2. 普通aop的匹配,是通过AspectJ的切点表达式来进行匹配,而事务看某个方法或者类是否命中了事务专有的Advisor,是通过解析@Transactional注解

1. aop是因为要解析切点表达式,来决定给那些bean生成动态代理对象。而事务就没那么复杂,只要看哪个类或者哪个类的方法上有@Transactional注解,就直接给它创建动态代理对象就好了。

2. 普通aop的解析切面,比较复杂,要把各种切面的注解解析成一个个Advisor。而事务的解析切面就简单了,Spring自己就提供了一个Advisor,都不需要去解析,直接就能拿到,拿到后事务的第一步解析切面的步骤就完成了

创建动态代理

Spring源码系列-Spring事务_第31张图片

Spring源码系列-Spring事务_第32张图片

Spring源码系列-Spring事务_第33张图片

Spring源码系列-Spring事务_第34张图片

如果使用第17行,那么使用这样的cglib动态代理时,在本类的一个方法中调用另一个方法,另一个方法也能有增强逻辑

而如果没有使用第17行,那么即便是使用了cglib动态代理时,在本类的一个方法中调用另一个方法,另一个方法也不会有增强逻辑

而spring事务的实现代码中,就算我们设置了proxyTargetClass为true,表示强制使用cglib动态代理,但是因为spring事务的实现代码没有使用上面第17行的调用方式,而是直接去调用了责任链,所以在本类的一个方法中调用另一个方法,另一个方法还是没有增强逻辑

调用代理方法

你可能感兴趣的:(spring)