您好,登錄后才能下訂單哦!
這篇文章主要講解了“spring源碼的@Transactional實現原理是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“spring源碼的@Transactional實現原理是什么”吧!
@Transactional注解簡介
spring中聲明式事務實現原理猜想
@Transactional作用
動態代理邏輯實現
TransactionInterceptor–最終事務管理者
總結
@Transactional是spring中聲明式事務管理的注解配置方式,相信這個注解的作用大家都很清楚。
@Transactional注解可以幫助我們把事務開啟、提交或者回滾的操作,通過aop的方式進行管理。
通過@Transactional注解就能讓spring為我們管理事務,免去了重復的事務管理邏輯,減少對業務代碼的侵入,使我們開發人員能夠專注于業務層面開發。
我們知道實現@Transactional原理是基于spring aop,aop又是動態代理模式的實現,通過對源碼的閱讀,總結出下面的步驟來了解實際中,在spring 是如何利用aop來實現@Transactional的功能的。如果對spring的aop實現原理不了解,可以看aop實現原理分析。
首先,對于spring中aop實現原理有了解的話,應該知道想要對一個方法進行代理的話,肯定需要定義切點。在@Transactional的實現中,同樣如此,spring為我們定義了以 @Transactional 注解為植入點的切點,這樣才能知道@Transactional注解標注的方法需要被代理。
有了切面定義之后,在spring的bean的初始化過程中,就需要對實例化的bean進行代理,并且生成代理對象。
生成代理對象的代理邏輯中,進行方法調用時,需要先獲取切面邏輯,@Transactional注解的切面邏輯類似于@Around,在spring中是實現一種類似代理邏輯。
根據上面的原理猜想,下面簡單介紹每個步驟的源碼以進行驗證。
首先是@Transactional,作用是定義代理植入點。【aop實現原理分析】中,分析知道代理對象創建的通過BeanPostProcessor的實現類AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInstantiation方法來實現個,如果需要進行代理,那么在這個方法就會返回一個代理對象給容器,同時判斷植入點也是在這個方法中。
那么下面開始分析,在配置好注解驅動方式的事務管理之后,spring會在ioc容器創建一個BeanFactoryTransactionAttributeSourceAdvisor實例,這個實例可以看作是一個切點,在判斷一個bean在初始化過程中是否需要創建代理對象,都需要驗證一次BeanFactoryTransactionAttributeSourceAdvisor是否是適用這個bean的切點。如果是,就需要創建代理對象,并且把BeanFactoryTransactionAttributeSourceAdvisor實例注入到代理對象中。
其中【aop實現原理分析】知道在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的作用一個就是標識方法需要被代理,一個就是攜帶事務管理需要的一些屬性信息。
【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#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(); } } }
最終可以總結一下整個流程,跟開始的猜想對照。
分析源碼后對照
感謝各位的閱讀,以上就是“spring源碼的@Transactional實現原理是什么”的內容了,經過本文的學習后,相信大家對spring源碼的@Transactional實現原理是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。