spring是如何实现声明式事务的
前言
有好长一段时间没写文章了,之前一直在找工作,如今工作换好了,可以继续写文章了,今天我们来讲讲spring的声明式事务。
开始
说到声明式事务,我们现在回顾一下事务这个概念,什么是事务呢,事务指的是逻辑上的⼀组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。从而确保了数据的准确与安全。事务有着四大特性(ACID),分别是
原子性(Atomicity)原⼦性是指事务是⼀个不可分割的⼯作单位,事务中的操作要么都发⽣,要么都不发⽣。
⼀致性(Consistency)事务必须使数据库从⼀个⼀致性状态变换到另外⼀个⼀致性状态。
在spring中,一共有两种方式可以实现事务控制,分别是编程式事务和声明式事务。编程式事务指的是在代码中添加事务控制代码,而声明式事务指的是利用xml或者注解的形式来配置控制事务,下面就以纯注解配置声明式事务为例进行剖析。
spring开启声明式事务的注解是@EnableTransactionManagement,讲到这里首先要明白一点,spring的事务管理器管理事务其实就是利用aop的方式,通过创建动态代理加上拦截,实现的事务管理。在spring的配置类中加上这个注解,就支持了声明式事务,那么spring是怎么通过这么一个注解就可以支持事务的呢,我们来看代码。
首先我们看到,在这个注解上,import了一个selector
@Import(TransactionManagementConfigurationSelector.class)
我们看这个selector类中的这么一段代码
@Overrideprotected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY:return new String[] {AutoProxyRegistrar.class.getName(),ProxyTransactionManagementConfiguration.class.getName()};case ASPECTJ:return new String[] {determineTransactionAspectClass()};default:return null;}}
这段代码中,引入了AutoProxyRegistrar和ProxyTransactionManagementConfiguration这两个类,我们先来看AutoProxyRegistrar这个类,这个类中有一段这样的代码
if (mode == AdviceMode.PROXY) {//重要的是这句代码AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);if ((Boolean) proxyTargetClass) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);return;}
}//我们进到这个方法中
@Nullablepublic static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {//可以看到引入了InfrastructureAdvisorAutoProxyCreator这个类,那么这个类又是什么呢return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);}//先看一下
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {@Nullableprivate ConfigurableListableBeanFactory beanFactory;@Overrideprotected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.initBeanFactory(beanFactory);this.beanFactory = beanFactory;}@Overrideprotected boolean isEligibleAdvisorBean(String beanName) {return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);}}
看一下继承结构图
可以看到这个方法间接继承于SmartInstantiationAwareBeanPostProcessor,最终继承于BeanPostProcessor,这说明InfrastructureAdvisorAutoProxyCreator类是一个后置处理器,并且跟 spring AOP 开启@EnableAspectJAutoProxy 时注册的AnnotationAwareAspectJProxyCreator实现的是同⼀个接口,这也对应了我之前所说声明式事务是springAOP思想的一种应用。
然后我们回过头来再看ProxyTransactionManagementConfiguration这个类,我们看到其中有一个事务增强器,一个属性解析器和是一个事务拦截器
@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;}@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;}
先看看属性解析器
//注解解析器集合private final Set<TransactionAnnotationParser> annotationParsers;
这是一个注解解析器的集合,可以添加多种注解解析器,在这里我们主要关注的是spring事务注解解析器SpringTransactionParser,看一下相关代码
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();// 对应Transaction注解的相关属性Propagation propagation = attributes.getEnum("propagation");rbta.setPropagationBehavior(propagation.value());Isolation isolation = attributes.getEnum("isolation");rbta.setIsolationLevel(isolation.value());rbta.setTimeout(attributes.getNumber("timeout").intValue());rbta.setReadOnly(attributes.getBoolean("readOnly"));rbta.setQualifier(attributes.getString("value"));List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {rollbackRules.add(new RollbackRuleAttribute(rbRule));}for (String rbRule : attributes.getStringArray("rollbackForClassName")) {rollbackRules.add(new RollbackRuleAttribute(rbRule));}for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {rollbackRules.add(new NoRollbackRuleAttribute(rbRule));}for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {rollbackRules.add(new NoRollbackRuleAttribute(rbRule));}rbta.setRollbackRules(rollbackRules);return rbta;}
可以看到这段代码中的Enum和ClassArray其实正是@Transaction注解中的相关属性,这个属性解析器的作用之一就是用来解析@Transaction注解中的属性
看完了属性解析器,我们接下来看事务拦截器TransactionInterceptor,其中重要的是这段代码
@Override@Nullablepublic Object invoke(MethodInvocation invocation) throws Throwable {// Work out the target class: may be {@code null}.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interface.Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupport's invokeWithinTransaction...// 增加事务支持return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);}
然后我们进到这个方法里面
@Nullableprotected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {// If the transaction attribute is null, the method is non-transactional.// 获取属性解析器,在配置类ProxyTransactionManagementConfiguration配置时加入TransactionAttributeSource tas = getTransactionAttributeSource();final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);final TransactionManager tm = determineTransactionManager(txAttr);if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {throw new TransactionUsageException("Unsupported annotated transaction on suspending function detected: " + method +". Use TransactionalOperator.transactional extensions instead.");}ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());if (adapter == null) {throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +method.getReturnType());}return new ReactiveTransactionSupport(adapter);});return txSupport.invokeWithinTransaction(method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);}// 获取事务管理器PlatformTransactionManager ptm = asPlatformTransactionManager(tm);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);Object retVal;try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exception// 目标方法抛异常,会执行回滚的操作completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {// Set rollback-only in case of Vavr failure matching our rollback rules...TransactionStatus status = txInfo.getTransactionStatus();if (status != null && txAttr != null) {retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);}}// 目标方法正常运行,会执行commitTransactionAfterReturning,执行事务提交操作commitTransactionAfterReturning(txInfo);return retVal;}else {final ThrowableHolder throwableHolder = new ThrowableHolder();// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.try {Object result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);try {Object retVal = invocation.proceedWithInvocation();if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {// Set rollback-only in case of Vavr failure matching our rollback rules...retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);}return retVal;}catch (Throwable ex) {if (txAttr.rollbackOn(ex)) {// A RuntimeException: will lead to a rollback.if (ex instanceof RuntimeException) {throw (RuntimeException) ex;}else {throw new ThrowableHolderException(ex);}}else {// A normal return value: will lead to a commit.throwableHolder.throwable = ex;return null;}}finally {cleanupTransactionInfo(txInfo);}});// Check result state: It might indicate a Throwable to rethrow.if (throwableHolder.throwable != null) {throw throwableHolder.throwable;}return result;}catch (ThrowableHolderException ex) {throw ex.getCause();}catch (TransactionSystemException ex2) {if (throwableHolder.throwable != null) {logger.error("Application exception overridden by commit exception", throwableHolder.throwable);ex2.initApplicationException(throwableHolder.throwable);}throw ex2;}catch (Throwable ex2) {if (throwableHolder.throwable != null) {logger.error("Application exception overridden by commit exception", throwableHolder.throwable);}throw ex2;}}}
总结
总体来说,spring实现声明式事务的过程是这样的
- @EnableTransactionManagement 注解,通过@import引⼊了TransactionManagementConfigurationSelector类,它的selectImports⽅法导⼊了另外两个类:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
- AutoProxyRegistrar类中方法registerBeanDefinitions中,通过 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)引⼊InfrastructureAdvisorAutoProxyCreator,是一个后置处理器类
- ProxyTransactionManagementConfiguration 是⼀个添加了@Configuration注解的配置类,注册了事务增强器(注⼊属性解析器、事务拦截器)AnnotationTransactionAttributeSource和TransactionInterceptor,AnnotationTransactionAttributeSource内部持有了⼀个解析器集合 Set<TransactionAnnotationParser> annotationParsers,具体使⽤的是SpringTransactionAnnotationParser解析器,用来解析@Transactional的事务属性,事务拦截器TransactionInterceptor实现了MethodInterceptor接⼝,该通用拦截会在产⽣代理对象之前和aop增强合并,最终⼀起影响到代理对象,TransactionInterceptor的invoke⽅法中invokeWithinTransaction会触发原有业务逻辑调用(增强事务)
spring是如何实现声明式事务的相关推荐
- 【Spring】Spring第三天 - 声明式事务、常用注解、Ajax 复习
一.自动注入 1.在Spring 配置文件中对象名和ref="id" . id 名相同,使用自动注入,可以不配置<property/> 2.两种配置办法 2.1 在&l ...
- 【Spring】spring基于注解的声明式事务控制
结构 domin package com.itheima.domain;import java.io.Serializable;public class Account implements Seri ...
- 【spring】spring基于xml的声明式事务控制
结构 domain package com.itheima.domain;import java.io.Serializable;public class Account implements Ser ...
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
事物管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的一致性. spring支持编程式事务管理和声明式事务管理两种方式. 编程式事务管理使用TransactionTemplate或 ...
- spring基于注解的声明式事务控制
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...
- spring基于XML的声明式事务控制-配置步骤
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...
- Spring基于 XML 的声明式事务控制(配置方式)
一.引入依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http ...
- Spring Hibernate使用TransactionInterceptor声明式事务配置
<!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.orm ...
- Spring 详解(五):Spring声明式事务
事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性.本文主要讲解事务涉及到一些概念以及spring中事务的使用. 1. 事务 数据库事务(Database Transaction) ...
最新文章
- 「云毕业照」刷爆朋友圈!AI人脸融合技术谁家强?
- 从MVC到云原生:CBU研发体系演进之路
- Elasticsearch Java 操作client
- 国家邮政局公布一项数据 春节期间快递数量依旧很猛!
- java activemq 断线_activemq 长时间没有消息client会断开吗?
- Unity NGUI中动态添加和删除sprite
- Ubuntu18.04取消VIM自动备份文件
- 《态度》- 吴军 四十封启明家书 读后感
- 用Camshift算法对指定目标进行跟踪
- JAVA实现UDP通信
- 概率论中几个入门公式
- 一文看雷击浪涌的防护解析
- 集线器、交换机、路由器功能原理入门总结
- 移植u-boot到stm32f407
- 移动端适配 - 小结
- 【Win 10应用开发】如何知道UAP在哪个平台上运行
- break语句和continue语句的区别
- Linux操作系统下/etc/hosts文件配置方法(域名映射)
- 【loj2639】[Tjoi2017]不勤劳的图书管理员
- 核心坚果计划互相监督跟踪平台 (New)
热门文章
- 保护你系统安全的影子系统
- 什么是点阵图 Bitmap ?
- 本周关注我们:节点,流星和网站性能
- 三万字加源码,教你从零开始学网页设计(HTML5+CSS)
- 实时同步刷新excel数据到数据库
- Arduino实验——GP2Y1014检测空气颗粒物浓度
- android 9.0谷歌商店,Android 10现可选择Play商店主题模式 附Android 9强制开启深色模式教程...
- php学习----php实现验证码
- TreeMap 底层原理
- 安卓3d游戏开发引擎_从德军总部3D到虚幻5,游戏引擎能有多大的飞跃?