深⼊理解Spring之SpringBoot事务原理
前⾔
今天是平安夜,先祝⼤家平安夜快乐。
我们之前的数⼗篇⽂章分析了 Spring 和 Mybatis 的原理,基本上从源码层⾯都了解了他们的基本原理,
那么。在我们⽇常使⽤这些框架的时候,还有哪些疑问呢?就楼主⽽⾔,楼主已经明⽩了 IOC ,AOP 的原理,也明⽩了 Mybatis 的原理,也明⽩了 Spring 和 Mybatis 是如何整合的。但是,我们漏掉了 JavaEE 中⼀个⾮常重要的特性:事务。事务是 Java 程序员开发程序时不可避免的问题。我们就不讨论ACID 的事务特性,楼主这⾥假定⼤家都已经了了解了事务的原理。如果还不了解,可以先去⾕歌看看。那么,我们今天的任务是剖析源码,看看Spring 是怎么运⾏事务的,并且是基于当前最流⾏的SpringBoot。还有,我们之前剖析Mybatis 的时候,也知道,Mybatis 也有事务,那么,他俩融合之后,事务是交给谁的?⼜是怎么切换的?今天这⼏个问题,我们都要从源码中到答案。
1. Spring 的事务如何运⾏?
如果各位使⽤过SpringBoot ,那么就⼀定知道如何在Spring中使⽤注解,⽐如在⼀个类或者⼀个⽅法上使⽤ @Transactional 注解,在⼀个配置类上加⼊⼀个 @EnableTransactionManagement 注解代表启动事务。⽽这个配置类需要实现TransactionManagementConfigurer 事务管理器配置接⼝。并实现 annotationDrivenTransactionManager ⽅法返回⼀个包含了 配置好数据源的 DataSourceTransactionManager 事务对象。这样就完成了事务配置,就可以在Spring使⽤事务的回滚或者提交功能了。
这个 saveList ⽅法就在Spring事务的控制之下,如果发⽣了异常,就会回滚事务。如果各位知道更多的Spring的事务特性,可以在注解中配置,⽐如什么异常才能回滚,⽐如超时时间,⽐如隔离级别,⽐如事务的传播。就更有利于理解今天的⽂章了。
我们基于⼀个 Junit 测试⽤例,来看看Spring的事务时如何运⾏的。
在测试⽤例中执⾏该⽅法,参数时⼀个空的List,这个Sql的运⾏肯定是失败的。我们主要看看他的运⾏过程。我们讲断点打在该⽅法上。断点进⼊该⽅法。
注意,dataCollectionShareService 对象已经被 Cglib 代理了,那么他肯定会⾛ DynamicAdvisedInterceptor 的 intercept ⽅法,我们断点进⼊该⽅法查看,这个⽅法我们已经很属性了,该⽅法中,最重要的事情就是执⾏通知器或者的⽅法,那么,该代理有通知器吗?
有⼀个通知器。是什么呢?
⼀个事务,也就是说,如果通知器链不为空,就会依次执⾏通知器链的⽅法。那么 TransactionInterceptor 到底是什么呢?
该类实现了通知器接⼝,也实现类 MethodInterceptor 接⼝,并实现了该接⼝的 invoke ⽅法,在 DynamicAdvisedInterceptor 的intercept ⽅法中,最终会调⽤每个 MethodInterceptor 的 invoke ⽅法,那么,TransactionInterceptor 的 invoke ⽅法是如何实现的呢?
invoke ⽅法中会调⽤⾃⾝的 invokeWithinTransaction ⽅法,看名字,该⽅法和事务相关。该⽅法参数是由⽬标⽅法,⽬标类,⼀个回调对象构成。 那么我们就进⼊该⽅法查看,该⽅法很长:
/**
* General delegate for around-advice-based subclasses, delegating to several other template
* methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}
* as well as regular {@link PlatformTransactionManager} implementations.
* @param method the Method being invoked
* @param targetClass the target class that we're invoking the method on
* @param invocation the callback to use for proceeding with the target invocation
* @return the return value of the method, if any
* @throws Throwable propagated from the target invocation
*/
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
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 {
// 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;
}
else {
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
if (llbackOn(ex)) {springboot框架的作用
// 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.
return new ThrowableHolder(ex);
}
}
finally {
cleanupTransactionInfo(txInfo);
}
}
});
// Check result: It might indicate a Throwable to rethrow.
if (result instanceof ThrowableHolder) {
throw ((ThrowableHolder) result).getThrowable();
}
else {
return result;
}
}
catch (ThrowableHolderException ex) {
Cause();
}
}
}
该⽅法主要逻辑:
1. 获取事务属性,根据事务属性,获取事务管理器。
2. 判断属性是否空,或者事务管理器是否不是 CallbackPreferringPlatformTransactionManager 类型,如果是该类型,则会执⾏事
务管理器的 execute ⽅法。
3. ⽣成⼀个封装了事务管理器,事务属性,⽅法签名字符串,事务状态对象 的 TransactionInfo 事务信息对象。该对象会在事务回滚或
者失败时起作⽤。
4. 调⽤⽬标对象⽅法或者是下⼀个过滤器的⽅法。
5. 如果⽅法由异常则执⾏ completeTransactionAfterThrowing ⽅法,调⽤事务管理器的回滚⽅法。如果没有异常,调⽤
commitTransactionAfterReturning 提交⽅法。最后返回返回值。
可以说,该⽅法就是Spring 事务的核⼼调⽤,根据⽬标⽅法是否有异常进⾏事务的回滚。
那么,我们需要⼀⾏⼀⾏的看看该⽅法实现。
⾸先看事务的属性。
2. TransactionAttribute 事务属性
invokeWithinTransaction ⽅法中调⽤了 ⾃⾝的 getTransactionAttributeSource ⽅法返回⼀个TransactionAttributeSource 对象,并调⽤该对象的 getTransactionAttribute ⽅法,参数是⽬标⽅法和⽬标类对象。⾸先看 getTransactionAttributeSource ⽅法,该⽅法直接返回了抽象类 TransactionAspectSupport 中定义的 TransactionAttributeSource 属性。该属性的是什么时候⽣成的我们稍后再说。我们debug 后返回的是 TransactionAttributeSource 接⼝的实现类 AnnotationTransactionAttributeSource ,看名字,注解事务属性资源,名字起的好很重要啊。我们进⼊该类查看。
这是该类的继承机构图。我们重点还是关注该类的 getTransactionAttribute ⽅法,该⽅法有抽象类AbstractFallbackTransactionAttributeSource 也就是 AnnotationTransactionAttributeSource 的⽗类完成。我们看看该⽅法。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。