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 ...
随机推荐
- 带拦截器配置的 struts.xml文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-/ ...
- P2822 组合数问题 HMR大佬讲解
今天HMR大佬给我们讲解了这一道难题. 基本思路是: 可以将问题转化为:求出杨辉三角,用二维数组f[i][j]来表示在杨辉三角中以第i行第j列的点为右下角,第0行第0列处的点为左上角的矩阵中所有元素是 ...
- 【XSY2988】取石子 博弈论
题目描述 有 \(n\) 堆石子,每堆石子的个数是 \(c_i\). Alice 和 Bob 轮流取石子(先后手未定),Alice 每次从一堆中取 \(a\) 个,Bob每次从一堆中取 \(b\) 个 ...
- 【51NOD1965】奇怪的式子 min_25筛
题目描述 给你\(n\),求 \[ \prod_{i=1}^n{\sigma_0(i)}^{i+\mu(i)} \] 对\({10}^{12}+39\)取模. \(\sigma_0(i)\)表示约数个 ...
- CSS概念,引入,选择器
概念 层叠样式表,定义如何显示HTML元素. 使用方式 行内样式 不推荐使用此方式 结构 和 样式的 杂糅会影响后期的维护 <p style="color: red"> ...
- iPhone各种机型尺寸、屏幕分辨率
px与pt区别 字体大小的设置单位,常用的有2种:px.pt.这两个有什么区别呢? 先搞清基本概念: px就是表示pixel,像素,是屏幕上显示数据的最基本的点: pt就是point,是印刷行业常用单 ...
- emwin 之 GUI_MessageBox 阻塞特性
2019-03-01 [小记] GUI_MessageBox 函数执行后必须手动点击关闭窗口,未关闭窗口前线程将阻塞在此处等待关闭窗口事件 [使用场景] 由于该函数不会产生任何消息, 所以可利用阻塞特 ...
- dajngo cache,throttling
缓存 背景介绍: 动态网站的问题就在于它是动态的. 也就是说每次用户访问一个页面,服务器要执行数据库查询,启动模板,执行业务逻辑以及最终生成一个你所看到的网页,这一切都是动态即时生成的. 从处理器资源 ...
- 通过nginx访问linux目录
http { ...... autoindex on; autoindex_exact_size off; autoindex_localtime on; server { listen 80; .. ...
- Gym - 101350A Sherlock Bones(思维)
The great dog detective Sherlock Bones is on the verge of a new discovery. But for this problem, he ...