1.前言
系统应用开发过程中通常需要使用事务来保证业务数据的一致性,实现方式如:开启事务、执行数据库写操作、提交或者回滚事务,这种标准实现方式适用于少量一致性业务,如果存在大量需要保证数据一致性的业务,不仅会让开发人员重复编码,还会给系统造成冗余代码。基于这些问题,伟大的Spring
框架为我们提供了@Transactional
注解,那么它是如何使用一个注解就解决了我们的烦恼呢?我们该如何着手进行分析呢?
SpringBoot
集成的功能往往要从一个xxxAutoConfiguration
开始说起
2.自动配置
打开TransactionAutoConfiguration
自动配置类可以看到一个比较重要的注解@EnableTransactionManagement
用于开启事务管理功能,@EnableTransactionManagement
注解又导入了AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
2.1 事务配置
ProxyTransactionManagementConfiguration
中声明了一个切面BeanFactoryTransactionAttributeSourceAdvisor
,看到切面必定会有相对应的切点TransactionAttributeSourcePointcut
(用于声明切入的范围)和通知TransactionInterceptor
(用于实现切入目标的后续操作)。
2.2 声明@Transactional
注解处理器
1 | java复制代码@Bean |
AnnotationTransactionAttributeSource
实例化指定了注解解析器为SpringTransactionAnnotationParser
可以看到该解析器主要用来处理@Transactional
注解
2.3 注入自动代理注册器
在2.自动配置
提到@EnableTransactionManagement
还引入了AutoProxyRegistrar
,向IOC
容器中注入InfrastructureAdvisorAutoProxyCreator
1 | java复制代码@Nullable |
InfrastructureAdvisorAutoProxyCreator
实现了BeanPostProcessor
接口,具有拦截并处理Bean
的能力
2.3.1 Bean
后置处理
1 | java复制代码@Override |
2.3.2 从容器中获取所有的Advisor
1 | java复制代码/** |
2.3.3 筛选出符合条件的Advisor
1 | java复制代码public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { |
判断方法上是否有@Transactional
注解,如果有则使用SpringTransactionAnnotationParser
进行解析并生成TransactionAttribute
2.3.4 Advisor
排序
1 | java复制代码sortAdvisors(eligibleAdvisors); |
2.3.4 小结
1 | java复制代码protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { |
2.4 选择代理方法
1 | java复制代码@Override |
2.4.1 生成代理
此处以cglib
为例
1 | java复制代码@Override |
1 | java复制代码private Callback[] getCallbacks(Class<?> rootClass) throws Exception { |
创建Enhancer
并指定回调为DynamicAdvisedInterceptor
2.5 调用代理
执行被代理对象目标方法userService.saveUser(user);
时会调用DynamicAdvisedInterceptor
的intercept()
方法
2.5.1 筛选满足条件的Advice
1 | java复制代码@Override |
2.5.2 执行满足条件的Advice
1 | java复制代码@Override |
- 事务调用
3.1 获取事务配置属性
1 | java复制代码TransactionAttributeSource tas = getTransactionAttributeSource(); |
也就是@Transactional
注解声明的属性
3.2 获取事务管理器
1 | java复制代码final TransactionManager tm = determineTransactionManager(txAttr); |
从容器中获取DataSourceTransactionManagerAutoConfiguration
自动配置类中声明的事务管理器JdbcTransactionManager
1 | java复制代码public class DataSourceTransactionManagerAutoConfiguration { |
3.3 执行事务
- 总结
@Transactional
实现原理三要素切面
、切点
、通知
InfrastructureAdvisorAutoProxyCreator
后置处理器拦截所有Bean
- 遍历所有类型为
Advisor
的切面
- 返回满足
切点
条件的切面
列表 - 选择代理方法
- 生成代理
- 调用
通知
的invoke()
方法- 开启事务
- 调用其它
通知
的invoke()
方法,如果没有执行目标方法 - 执行异常,回滚事务
- 执行成功,提交事务
- 执行目标方法
了解@Transactional
注解实现原理,不仅可以让我们对切面
、切点
、通知
有一个清晰的认识,还可以让我们通过其思想实现类似功能,如@Cache
注解实现应用缓存,@Async
注解实现业务异步执行
本文转载自: 掘金