共计 7036 个字符,预计需要花费 18 分钟才能阅读完成。
@Transactional 注解简介
@Transactional
是 spring 中申明式事务管理的注解配置形式,置信这个注解的作用大家都很分明。@Transactional
注解能够帮忙咱们把事务开启、提交或者回滚的操作,通过 aop 的形式进行治理。
通过 @Transactional
注解就能让 spring 为咱们治理事务,免去了反复的事务管理逻辑,缩小对业务代码的侵入,使咱们开发人员可能专一于业务层面开发。
咱们晓得实现 @Transactional 原理是基于 spring aop,aop 又是动静代理模式的实现,通过对源码的浏览,总结出上面的步骤来理解理论中,在 spring 是如何利用 aop 来实现 @Transactional 的性能的。
spring 中申明式事务实现原理猜测
首先,对于 spring 中 aop 实现原理有理解的话,应该晓得想要对一个办法进行代理的话,必定须要定义切点。在 @Transactional 的实现中,同样如此,spring 为咱们定义了以 @Transactional 注解为植入点的切点,这样能力晓得 @Transactional 注解标注的办法须要被代理。
有了切面定义之后,在 spring 的 bean 的初始化过程中,就须要对实例化的 bean 进行代理,并且生成代理对象。
生成代理对象的代理逻辑中,进行办法调用时,须要先获取切面逻辑,@Transactional 注解的切面逻辑相似于 @Around,在 spring 中是实现一种相似代理逻辑。
@Transactional 作用
依据下面的原理猜测,上面简略介绍每个步骤的源码以进行验证。
首先是 @Transactional,作用是定义代理植入点。咱们晓得代理对象创立的通过 BeanPostProcessor
的实现类 AnnotationAwareAspectJAutoProxyCreator
的postProcessAfterInstantiation
办法来实现个,如果须要进行代理,那么在这个办法就会返回一个代理对象给容器,同时判断植入点也是在这个办法中。
那么上面开始剖析,在配置好注解驱动形式的事务管理之后,spring 会在 ioc 容器创立一个 BeanFactoryTransactionAttributeSourceAdvisor
实例,这个实例能够看作是一个切点,在判断一个 bean 在初始化过程中是否须要创立代理对象,都须要验证一次 BeanFactoryTransactionAttributeSourceAdvisor
是否是实用这个 bean 的切点。如果是,就须要创立代理对象,并且把 BeanFactoryTransactionAttributeSourceAdvisor
实例注入到代理对象中。
前文咱们晓得在 AopUtils#findAdvisorsThatCanApply
中判断切面是否实用以后 bean,能够在这个中央断点剖析调用堆栈,AopUtils#findAdvisorsThatCanApply
统一调用,最终通过以下代码判断是否实用切点。
AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Method method, Class<?> targetClass)
这里能够依据参数打上条件断点进行调试剖析调用栈,targetClass 就是指标 class …一系列调用- 最终
SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
@Override
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
// 这里就是剖析 Method 是否被 @Transactional 注解标注,有的话,不用说 BeanFactoryTransactionAttributeSourceAdvisor 适配以后 bean,进行代理,并且注入切点
//BeanFactoryTransactionAttributeSourceAdvisor
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
if (attributes != null) {return parseTransactionAnnotation(attributes);
}
else {return null;}
}
下面就是判断是否须要依据 @Transactional 进行代理对象创立的判断过程。@Transactional 的作用一个就是标识办法须要被代理,一个就是携带事务管理须要的一些属性信息。
举荐一个 Spring Boot 基础教程及实战示例:
https://github.com/javastacks…
动静代理逻辑实现
【aop 实现原理剖析】中晓得,aop 最终的代理对象的代理办法是
DynamicAdvisedInterceptor#intercept
所以咱们能够在这个办法断点剖析代理逻辑。
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {targetClass = target.getClass();
}
//follow
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {if (target != null) {releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
通过剖析 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
返回的是 TransactionInterceptor, 利用 TransactionInterceptor 是如何实现代理逻辑调用的?
跟踪new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
发现最终是调用 TransactionInterceptor#invoke
办法,并且把 CglibMethodInvocation 注入到 invoke 办法中,从下面能够看到 CglibMethodInvocation
是包装了指标对象的办法调用的所有必须信息,因而,在 TransactionInterceptor#invoke
外面也是能够调用指标办法的,并且还能够实现相似 @Around 的逻辑,在指标办法调用前后持续注入一些其余逻辑,比方事务管理逻辑。
TransactionInterceptor–最终事务管理者
上面看代码。
TransactionInterceptor#invoke
@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();
}
});
}
持续跟踪 invokeWithinTransaction,上面的代码中其实就能够看出一些逻辑端倪,就是咱们猜测的实现形式,事务管理。
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);
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 (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.
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) {throw ex.getCause();
}
}
}
总结
最终能够总结一下整个流程,跟开始的猜测对照。
剖析源码后对照
原文链接:https://blog.csdn.net/qq_2059…
版权申明:本文为 CSDN 博主「一撸向北」的原创文章,遵循 CC 4.0 BY-SA 版权协定,转载请附上原文出处链接及本申明。
近期热文举荐:
1.1,000+ 道 Java 面试题及答案整顿(2021 最新版)
2. 别在再满屏的 if/ else 了,试试策略模式,真香!!
3. 卧槽!Java 中的 xx ≠ null 是什么新语法?
4.Spring Boot 2.5 重磅公布,光明模式太炸了!
5.《Java 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!