Spring注解式事务解析
Spring注解式事务解析
增加一个Advisor
首先往Spring容器新增一个Advisor,BeanFactoryTransactionAttributeSourceAdvisor,它包含了TransactionInterceptor通知和TransactionAttributeSourcePointcut切点。TransactionAttributeSourcePointcut切点实际匹配使用了AnnotationTransactionAttributeSource这个类,它的作用是方法的切点匹配,解析Transactional注解,它尝试从当前类的方法,当前类,父接口方法,父接口查找Transactional注解,有则匹配到。AOP动态代理
当普通bean实例化的时候,Spring通过AbstractAdvisorAutoProxyCreator的其中一个子类进行postProcessAfterInitialization进行AOP这个bean,织入匹配的Advisor,并生成动态代理。动态代理有2种,JdkDynamicAopProxy和ObjenesisCglibAopProxy。拦截过程
方法调用的时候,拿JdkDynamicAopProxy动态代理来讲,被动态代理的bean的公有方法调用会走invoke方法拦截,首先确定当前方法的拦截器链。List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
如果上面的chain为空,不走拦截,否则走拦截责任链
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
TransactionInterceptor事务拦截器
内部拿到我们的TransactionInterceptor进行方法调用@Override
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, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
5.创建TransactionInfo对象
他会先获取TransactionAttribute和PlatformTransactionManager,然后调用
```
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
```
内部逻辑为拿DataSourceTransactionManager举例,
尝试从ThreadLocal获取ConnectionHolder(包含了一个Connection)
```
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
```
然后判断是不是新事务
```
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
```
不是新事务,走handleExistingTransaction逻辑,内部会根据我们配置的传递规则做不同的处理,默认的Propagation.REQUIRED就会返回TransactionStatus对象标志为已存在的事务。
是新事务则返回TransactionStatus对象标志为新事务,代码如下:
```
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
```
doBegin方法会从dataSource获取一个新连接,并设置到DataSourceTransactionObject的ConnectionHolder字段里,并且设置synchronizedWithTransaction和transactionActive为true代表新事务,然后设置con.setAutoCommit(false),最后设置ThreadLocal值,为当前ConnectionHolder。
```
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
```
6.责任链调用下一个拦截器
获取了当前的TransactionInfo开始走下一个拦截器
```
Object retVal = null;
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;
}
```
7.提交或回滚
处理完了之后如果抛异常根据匹配规则是否需要回滚,默认对RuntimeException和Error回滚。如果正常返回则调用commitTransactionAfterReturning方法
```
protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
if (txInfo != null && txInfo.hasTransaction()) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
```
进行commit,最后调用doCleanupAfterCompletion方法,清空ThreadLocal,设置con.setAutoCommit(true),并关闭连接。
Spring注解式事务解析的更多相关文章
- spring + mybatis 注解式事务不回滚的原因分析 @Transactional
在一个项目中发现spring的事务无法回滚. DEBUG: org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.ses ...
- spring中注解式事务不生效的问题
常用的解决方法可以百度,我针对我的问题描述一下 Mysql中InnoDB引擎才支持事务, MyISAM不支持事务. 当你尝试了各种方法解决spring中注解式事务不生效时, 一定要查看一下数据库中表的 ...
- spring+mybatis之注解式事务管理初识(小实例)
1.上一章,我们谈到了spring+mybatis声明式事务管理,我们在文章末尾提到,在实际项目中,用得更多的是注解式事务管理,这一章将学习一下注解式事务管理的有关知识.注解式事务管理只需要在上一节的 ...
- Spring 16: SM(Spring + MyBatis) 注解式事务 与 声明式事务
Spring事务处理方式 方式1:注解式事务 使用@Transactional注解完成事务控制,此注解可添加到类上,则对类中所有方法执行事务的设定,注解添加到方法上,则对该方法执行事务处理 @Tran ...
- 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。
基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...
- Spring -- <tx:annotation-driven>注解基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)的区别。
借鉴:http://jinnianshilongnian.iteye.com/blog/1508018 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional ...
- spring注解式参数校验
很痛苦遇到大量的参数进行校验,在业务中还要抛出异常或者返回异常时的校验信息,在代码中相当冗长,今天我们就来学习spring注解式参数校验. 其实就是:hibernate的validator. 开始啦. ...
- Spring注解开发-全面解析常用注解使用方法之生命周期
本文github位置:https://github.com/WillVi/Spring-Annotation/ 往期文章:Spring注解开发-全面解析常用注解使用方法之组件注册 bean生命周期 ...
- -手写Spring注解版本&事务传播行为
视频参考C:\Users\Administrator\Desktop\蚂蚁3期\[www.zxit8.com] 0018-(每特教育&每特学院&蚂蚁课堂)-3期-源码分析-手写Spri ...
随机推荐
- Arrays 三种基本常用法
一:背景 jdk中为了便于开发,给开发者提供了Arrays类,其中包含了很多数组的常用操作.例如快速输出.排序.查找等 二: import java.util.Arrays; //(需要引用class ...
- 【题解】放球游戏A
题目描述 校园里在上活动课,Red和Blue两位小朋友在玩一种游戏,他俩在一排N个格子里,自左到右地轮流放小球,每个格子只能放一个小球.每个人一次只能放1至5个球,最后面对没有空格而不能放球的人为输. ...
- Django+Vue打造购物网站(七)
个人中心功能开发 drf文档注释 http://www.django-rest-framework.org/topics/documenting-your-api/ 动态设置serializer和pe ...
- for循环里使用查询如何优化(代码库)
for循环里的查询,只是为了赋值对象中的一个字段,如果每一个都重新查一下数据库,影响效率 应该先进行查询,然后再循环里组装自己需要的业务数据 如下代码:list1 查询出对象的一部分内容,list2 ...
- OpenFlow 交换机与控制器交互步骤
1. Hello 控制器与交互及互相发送 Hello 消息.Hello消息中只包含有OpenFlow Header,其中的 type 字段为 OFPT_HELLO,version 字段为发送方所支持的 ...
- NOI真题记录
NOI2001 食物链,拓展域并查集. 炮兵阵地,棋盘状压DP. NOI2002 银河英雄传说,kruskal重构树/带权并查集. 贪吃的九头龙,树形DP. NOI2003 逃学的小孩,树形DP,二次 ...
- 主机管理+堡垒机系统开发:strace工具的实现原理(七)
strace是Linux系统下的一个用来跟踪系统调用的工具,它的实现基础是ptrace系统调用.使用strace工具可以跟踪一个程序执行过程中发生的系统调用. 我这里讲到的内容有一点点和mips体系相 ...
- 解决Java getResource 路径中含有中文的情况
问题描述 当Java调用getResource方法,但是因为路径中含有中文时,得不到正确的路径 问题分析 编码转换问题 当我们使用ClassLoader的getResource方法获取路径时,获取到的 ...
- /etc/profile文件被改坏导致命令不可用
这几天在装一个软件,设置环境变量的时候,不小心把/etc/profile文件改坏了(就是没配置对),在source /etc/profile后导致所有命令都不可用了.出现如下报错: -bash: xx ...
- JAVA写JSON的三种方法,java对象转json数据
JAVA写JSON的三种方法,java对象转json数据 转自:http://www.xdx97.com/#/single?bid=5afe2ff9-8cd1-67cf-e7bc-437b74c07a ...