@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开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!
发表回复