@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)
@Overridepublic 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
所以咱们能够在这个办法断点剖析代理逻辑。
@Overridepublic 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
@Overridepublic 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开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!