2019独角兽企业重金招聘Python工程师标准>>>

通常Spring事务管理的配置都是XML或者声明式注解的方式,然后想要学习其运行的原理,从TransactionProxyFactoryBean深入更合适。我们从事务相关的核心类开始,逐步介绍Spring事务的运行机制。

Spring事务核心类

Spring事务的构成,基本有三个部分,事务属性的定义,事务对象及状态信息的持有,事务管理器的处理。

事务属性的定义

  1. TransactionDefinition 事务定义(传播属性,隔离属性,timeout等)
  2. TransactionAttribute 事务属性接口 (继承TransactionDefinition),常用的实现是RuleBasedTransactionAttribute
  3. TransactionAttributeSource 事务属性数据源,可以根据method和Class获取TransactionAttribute(注解方式的实现为AnnotationTransactionAttributeSource,编程方式的实现为NameMatchTransactionAttributeSource)

事务对象及状态信息的持有

  1. Transaction 事务对象,由具体的事务管理器实现返回
  2. TransactionStatus 事务状态,持有事务对象以及事务本身的属性及状态,每次事务方法执行前,生成一个新的TransactionStatus,但如果不需要创建新事务,则持有的事务和上层一致
  3. TransactionInfo 事务信息,持有事务属性,事务状态,事务连接点(方法路径),事务管理器,每次事务方法执行,生成新的TransactionInfo,并且绑定到当前线程(ThreadLocal),同时持有上一事务信息对象,形成链式结构。

事务管理器的处理

  1. PlatformTransactionManager事务管理接口,AbstractPlatformTransactionManager为其抽象实现(实现了getTransaction,commit,rollback模板方法),常用的实现如JDBC的事务管理实现DataSourceTransactionManager

TransactionProxyFactoryBean

TransactionProxyFactoryBean实现了FactoryBean和InitializingBean接口,FactoryBean支持对需要事务支持的类的代理,InitializingBean初始化事务环境的准备工作,完成代理对象的创建。我们再来看下xml的配置:

<!-- userManager事务代理类 -->
<bean id="userManagerTransactionProxy"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"><!-- 原始对象 --><property name="target" ref="userManager"/><!-- 事务属性 --><property name="transactionAttributes"><props><prop key="batchOperator">PROPAGATION_REQUIRED,readOnly</prop></props></property><!-- 事务管理器 --><property name="transactionManager"><bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean></property>
</bean>

需要配置的有三个,原始对象,事务属性和事务管理器。其中原始对象用来生成代理对象,而事务属性和事务管理器都设置到一个很重要的对象中,即TransactionInterceptor,事务拦截器,对应AOP中的增强类,完成事务管理和方法本身的结合。

回到TransactionProxyFactoryBean的构造,其主要实现定义在抽象父类AbstractSingletonProxyFactoryBean中。在初始化方法afterPropertiesSet中,使用最原始的ProxyFactory, 完成了代理对象的创建。

AbstractSingletonProxyFactoryBean.javapublic void afterPropertiesSet() {if (this.target == null) {throw new IllegalArgumentException("Property 'target' is required");}if (this.target instanceof String) {throw new IllegalArgumentException("'target' needs to be a bean reference, not a bean name as value");}if (this.proxyClassLoader == null) {this.proxyClassLoader = ClassUtils.getDefaultClassLoader();}// 创建AOP代理工厂ProxyFactory proxyFactory = new ProxyFactory();// 添加前置增强拦截器if (this.preInterceptors != null) {for (Object interceptor : this.preInterceptors) {proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));}}// 核心增强拦截器,有子类实现,在TransactionProxyFactoryBean中即是TransactionInterceptor// Add the main interceptor (typically an Advisor).proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));// 添加后置增强拦截器if (this.postInterceptors != null) {for (Object interceptor : this.postInterceptors) {proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));}}// 拷贝AOP的基本配置,如exposeProxy等proxyFactory.copyFrom(this);// 设置原始对象TargetSource targetSource = createTargetSource(this.target);proxyFactory.setTargetSource(targetSource);// 设置原始对象实现的接口if (this.proxyInterfaces != null) {proxyFactory.setInterfaces(this.proxyInterfaces);}else if (!isProxyTargetClass()) {// Rely on AOP infrastructure to tell us what interfaces to proxy.Class<?> targetClass = targetSource.getTargetClass();if (targetClass != null) {proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));}}// 对proxyFactory的后置处理postProcessProxyFactory(proxyFactory);// 代理工厂生成代理对象this.proxy = proxyFactory.getProxy(this.proxyClassLoader);
}

其中核心增强拦截器有子类实现其创建方法createMainInterceptor

TransactionProxyFactoryBean.javaprotected Object createMainInterceptor() {// 初始化TransactionInterceptorthis.transactionInterceptor.afterPropertiesSet();if (this.pointcut != null) {// 有pointcut的生成DefaultPointcutAdvisorreturn new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);}else {// Rely on default pointcut.// 没有pointcut的依赖默认的pointcutreturn new TransactionAttributeSourceAdvisor(this.transactionInterceptor);}
}

TransactionAttributeSourceAdvisor的默认pointcut类是TransactionAttributeSourcePointcut,定义在其内部。

TransactionAttributeSourceAdvisor.javaprivate final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {@Override@Nullableprotected TransactionAttributeSource getTransactionAttributeSource() {return (transactionInterceptor != null ? transactionInterceptor.getTransactionAttributeSource() : null);}
};

TransactionAttributeSourcePointcut是一个抽象类,在TransactionAttributeSourceAdvisor匿名实现的。我们来看下TransactionAttributeSourcePointcut的实现,它继承了StaticMethodMatcherPointcut,一个对方法进行匹配的基本Pointcut类,实现matches方法。

public boolean matches(Method method, @Nullable Class<?> targetClass) {if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {return false;}// 获取事务属性数据源TransactionAttributeSource tas = getTransactionAttributeSource();// 根据方法和Class对象获取是否有事务属性配置存在,来决定是否切入事务AOPreturn (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

而事务属性数据源从哪里设置的呢?我们在上面的TransactionAttributeSourceAdvisor匿名实现的TransactionAttributeSourcePointcut类中可以发现TransactionAttributeSource是从TransactionInterceptor中获取的。而TransactionInterceptor的TransactionAttributeSource是哪里设置的呢?来源于XML配置的properties对象transactionAttributes,在TransactionProxyFactoryBean的setTransactionAttributes方法中。

public void setTransactionAttributes(Properties transactionAttributes) {this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
}

transactionAttributes实际被设置到TransactionInterceptor中

public void setTransactionAttributes(Properties transactionAttributes) {NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();tas.setProperties(transactionAttributes);this.transactionAttributeSource = tas;
}

这里看到TransactionAttributeSource的实现是NameMatchTransactionAttributeSource。在其内部维护了一个方法名和事务属性的Map

private Map<String, TransactionAttribute> nameMap = new HashMap<>();

因此对哪个方法进行事务AOP的切入的原理就很清楚了。接下来就是核心拦截器TransactionInterceptor的解析。

TransactionInterceptor

TransactionInterceptor实现了Spring AOP的基本增加接口MethodInterceptor,实现invoke方法

public Object invoke(final 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);
}

具体实现由TransactionInterceptor抽象子类TransactionAspectSupport的invokeWithinTransaction方法执行

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {// If the transaction attribute is null, the method is non-transactional.// 获取事务属性数据源,如果为null,则此方法为非事务环境TransactionAttributeSource tas = getTransactionAttributeSource();// 获取事务属性final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);// 根据事务属性决定事务管理器对象final PlatformTransactionManager tm = determineTransactionManager(txAttr);// 连接点标识,一般就是方法名final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.// 创建事务对象,并返回事务信息TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal = null;// 环绕增强实现,try中为方法本身的执行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);}// 方法执行成功后事务提交的处理commitTransactionAfterReturning(txInfo);return retVal;}// ...

这个方法就是事务执行的核心部分,通过环绕增加,完成方法不同执行结果(成功或异常)对应事务的处理。当然前提是要先创建事务,来看createTransactionIfNecessary方法

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {// If no name specified, apply method identification as transaction name.if (txAttr != null && txAttr.getName() == null) {txAttr = new DelegatingTransactionAttribute(txAttr) {@Overridepublic String getName() {return joinpointIdentification;}};}TransactionStatus status = null;if (txAttr != null) {if (tm != null) {// 由事务管理器创建事务状态对象status = tm.getTransaction(txAttr);}else {if (logger.isDebugEnabled()) {logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +"] because no transaction manager has been configured");}}}// 填充事务状态对象的其他信息return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

事务对象及状态的维护由具体的事务管理器来管理,下一章我们具体讨论事务管理器,这里主要关注它的构建骨架。返回的事务状态对象TransactionStatus,需要再次被prepareTransactionInfo方法填充

protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, String joinpointIdentification,@Nullable TransactionStatus status) {// 创建事务信息对象,记录事务管理器,事务属性,及事务切入点信息TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);if (txAttr != null) {// 记录事务状态txInfo.newTransactionStatus(status);}else {if (logger.isTraceEnabled())logger.trace("Don't need to create transaction for [" + joinpointIdentification +"]: This method isn't transactional.");}// We always bind the TransactionInfo to the thread, even if we didn't create// a new transaction here. This guarantees that the TransactionInfo stack// will be managed correctly even if no transaction was created by this aspect.// 绑定事务信息对象和当前线程,并在当前事务信息对象中记录线程原来绑定的事务信息对象,从而保证了事务信息栈的管理txInfo.bindToThread();return txInfo;
}

这里非常重要的是维护了一个线程级别的事务信息的栈结构。

事务信息组建完成后,就是方法本身的执行。如果发生异常,则事务该如何处理,由completeTransactionAfterThrowing方法执行

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {if (txInfo != null && txInfo.getTransactionStatus() != null) {if (logger.isTraceEnabled()) {logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +"] after exception: " + ex);}// 校验当前异常是否要回滚事务,如果是,则执行回滚操作,如果不是,则执行提交操作if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {try {txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());}catch (TransactionSystemException ex2) {logger.error("Application exception overridden by rollback exception", ex);ex2.initApplicationException(ex);throw ex2;}catch (RuntimeException ex2) {logger.error("Application exception overridden by rollback exception", ex);throw ex2;}catch (Error err) {logger.error("Application exception overridden by rollback error", ex);throw err;}}else {// We don't roll back on this exception.// Will still roll back if TransactionStatus.isRollbackOnly() is true.try {txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());}catch (TransactionSystemException ex2) {logger.error("Application exception overridden by commit exception", ex);ex2.initApplicationException(ex);throw ex2;}catch (RuntimeException ex2) {logger.error("Application exception overridden by commit exception", ex);throw ex2;}catch (Error err) {logger.error("Application exception overridden by commit error", ex);throw err;}}}
}

在上面的方法中,核心就是判断原始方法抛出的异常是否要回滚事务,如果是,则调用事务管理器回滚事务,如果不是,则直接提交事务。

对异常是否回滚事务的判断是由事务属性中的rollbackFor和noRollbackFor共同决定的,默认都没有配置时,执行DefaultTransactionAttribute基本事务属性类中的rollbackOn方法

public boolean rollbackOn(Throwable ex) {return (ex instanceof RuntimeException || ex instanceof Error);
}

即当异常为运行时异常或Error时,就会回滚,否则直接提交。直接提交这一点也是需要格外注意的。

如果方法运行没有异常,执行完成后,就需要提交事务,由commitTransactionAfterReturning方法执行

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {if (txInfo != null && txInfo.getTransactionStatus() != null) {if (logger.isTraceEnabled()) {logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");}txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());}
}

调用事务管理器执行commit来提交事务。

至此,对于TransactionProxyFactoryBean的AOP代理生成以及TransactionInterceptor核心增强中事务执行的原理都基本解析清楚了,下一章介绍事务管理器的运行机制以及DataSourceTransactionManager如何和JDBC事务接口的交互。

转载于:https://my.oschina.net/u/2377110/blog/1611531

Spring事务管理(二)-TransactionProxyFactoryBean原理相关推荐

  1. Spring事务管理的实现原理

    Spring事务管理的实现原理 文章目录 Spring事务管理的实现原理 背景 正文 第一轮学习:总体分析,目标确认 总体分析 第二轮学习:正式进入源码,寻找突破口 第二次分析 总结 第三轮学习:研究 ...

  2. Spring事务管理(三)-PlatformmTransactionManager解析和事务传播方式原理

    2019独角兽企业重金招聘Python工程师标准>>> Spring在事务管理时,对事务的处理做了极致的抽象,即PlatformTransactionManager.对事务的操作,简 ...

  3. 分析Spring事务管理原理及应用

    目录 一.Spring事务管理介绍 (一)基本理论 (二)实际工作中的举例 (三)简单应用举例 二.Spring事务配置介绍 (一)Spring事务属性介绍 传播属性(传播行为)可选值说明 (二)声明 ...

  4. spring事务管理 TransactionProxyFactoryBean源码分析

    J2EE,当然离不开事务,事务又当然少不了Spring声明式事务.spring声明式事务,很多码农门,应该和笔者一样,停留在使用上,及仅仅了解点原理.如:Spring事务管理原理"代理+AO ...

  5. springaop事务逻辑原理_架构师:一篇文章掌握——Spring 事务管理

    对大多数Java开发者来说,Spring事务管理是Spring应用中最常用的功能,使用也比较简单.本文主要逐步介绍Spring事务管理的相关知识点及原理,作为Spring事务管理的学习总结. 一.关键 ...

  6. Spring 事务管理@transactional 的实现原理和使用

    转载自:http://tech.lede.com/2017/02/06/rd/server/SpringTransactional/ 本文主要讨论Spring声明式事务中使用注解@Transactio ...

  7. Spring声明式事务管理实现及原理详解

    目录 1.实现步骤 1.1.配置事务管理器 1.2.启动事务注解 1.3.业务添加注解 2.代码演示 2.1.bean文件 2.2.目标类 2.3.测试类 3.Spring事务属性 3.1.传播行为 ...

  8. Spring事务管理知识概述

    本文记录下Spring事务管理的主要内容. 文章目录 概述 事务回顾 事务的API介绍 PlatformTransactionManager接口 PlatformTransactionManager定 ...

  9. Spring事务管理-》Spring事务管理(annotation)

    5.6 使用@Transactional 除了使用XML类型的事务管理,同时Spring也提供了Annotation类型的事务管理.如下所示: 一:Spring事务管理 =============== ...

最新文章

  1. 皮一皮:叛徒可耻!!!
  2. mysql int 默认值 为ull_数据类型--ULL、ll
  3. [转]Device Context 设备环境 设备上下文 理解
  4. 连载四:Oracle升级文章大全(完结篇)
  5. winafl 源码分析
  6. 我们都是孩子。』凄美的爱情青春
  7. 解决ajax中文乱码问题
  8. c++ 中文字符的 setw 格式化打印问题
  9. 曝光三要素:光圈、快门、ISO
  10. 沉浸式体验娱乐,通往元宇宙之路?
  11. Several ports (8005, 8080, 8009) required by demo are already in use. The server may already be runn
  12. Gartner:2018年前沿技术预测
  13. Rxjava源码初理解(一)
  14. Oracle SQL前三行,后三行
  15. SVN提交,报“remains in conflict”错误
  16. 计算墨水污染的格子【非常规墨水污染】
  17. 保姆级教程:顶会论文写作指南
  18. 细思极恐!使用 AI 控制你的浏览器
  19. JavaScript mongodb(数据库)简单值
  20. Phenix图文流程:使用docking解决Cryo-EM数据的结构问题

热门文章

  1. 测试基础【第二篇】软件测试模型
  2. 设置searchDisplayController的searchResultsTableView的UITableViewStyle为grouped
  3. 无向图的邻接表表示法 及 深搜遍历DFS
  4. Python3列表、元组及之间的区别和转换
  5. 圆柱与平面接触宽度_好烦!这个建筑高大斜圆柱真难施工!别怕!学会这种工法就不难了...
  6. linux启动mysql_Linux安装mysql
  7. 事务例子_图文详解:数据库事务与锁
  8. 学java出来工作会很忙吗?
  9. 8年前端开发的知识点沉淀(不知道会多少字,一直写下去吧...)
  10. 应该怎么样学习前端呢?