欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring源碼閱讀--@Transactional實(shí)現(xiàn)原理講解

 更新時(shí)間:2021年09月28日 11:56:06   作者:一擼向北  
這篇文章主要介紹了spring源碼閱讀--@Transactional實(shí)現(xiàn)原理講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

@Transactional注解簡(jiǎn)介

@Transactional是spring中聲明式事務(wù)管理的注解配置方式,相信這個(gè)注解的作用大家都很清楚。

@Transactional注解可以幫助我們把事務(wù)開(kāi)啟、提交或者回滾的操作,通過(guò)aop的方式進(jìn)行管理。

通過(guò)@Transactional注解就能讓spring為我們管理事務(wù),免去了重復(fù)的事務(wù)管理邏輯,減少對(duì)業(yè)務(wù)代碼的侵入,使我們開(kāi)發(fā)人員能夠?qū)W⒂跇I(yè)務(wù)層面開(kāi)發(fā)。

在這里插入圖片描述

我們知道實(shí)現(xiàn)@Transactional原理是基于spring aop,aop又是動(dòng)態(tài)代理模式的實(shí)現(xiàn),通過(guò)對(duì)源碼的閱讀,總結(jié)出下面的步驟來(lái)了解實(shí)際中,在spring 是如何利用aop來(lái)實(shí)現(xiàn)@Transactional的功能的。如果對(duì)spring的aop實(shí)現(xiàn)原理不了解,可以看aop實(shí)現(xiàn)原理分析。

spring中聲明式事務(wù)實(shí)現(xiàn)原理猜想

  • 首先,對(duì)于spring中aop實(shí)現(xiàn)原理有了解的話,應(yīng)該知道想要對(duì)一個(gè)方法進(jìn)行代理的話,肯定需要定義切點(diǎn)。在@Transactional的實(shí)現(xiàn)中,同樣如此,spring為我們定義了以 @Transactional 注解為植入點(diǎn)的切點(diǎn),這樣才能知道@Transactional注解標(biāo)注的方法需要被代理。
  • 有了切面定義之后,在spring的bean的初始化過(guò)程中,就需要對(duì)實(shí)例化的bean進(jìn)行代理,并且生成代理對(duì)象。
  • 生成代理對(duì)象的代理邏輯中,進(jìn)行方法調(diào)用時(shí),需要先獲取切面邏輯,@Transactional注解的切面邏輯類似于@Around,在spring中是實(shí)現(xiàn)一種類似代理邏輯。

在這里插入圖片描述

@Transactional作用

根據(jù)上面的原理猜想,下面簡(jiǎn)單介紹每個(gè)步驟的源碼以進(jìn)行驗(yàn)證。

首先是@Transactional,作用是定義代理植入點(diǎn)?!綼op實(shí)現(xiàn)原理分析】中,分析知道代理對(duì)象創(chuàng)建的通過(guò)BeanPostProcessor的實(shí)現(xiàn)類AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInstantiation方法來(lái)實(shí)現(xiàn)個(gè),如果需要進(jìn)行代理,那么在這個(gè)方法就會(huì)返回一個(gè)代理對(duì)象給容器,同時(shí)判斷植入點(diǎn)也是在這個(gè)方法中。

那么下面開(kāi)始分析,在配置好注解驅(qū)動(dòng)方式的事務(wù)管理之后,spring會(huì)在ioc容器創(chuàng)建一個(gè)BeanFactoryTransactionAttributeSourceAdvisor實(shí)例,這個(gè)實(shí)例可以看作是一個(gè)切點(diǎn),在判斷一個(gè)bean在初始化過(guò)程中是否需要?jiǎng)?chuàng)建代理對(duì)象,都需要驗(yàn)證一次BeanFactoryTransactionAttributeSourceAdvisor是否是適用這個(gè)bean的切點(diǎn)。如果是,就需要?jiǎng)?chuàng)建代理對(duì)象,并且把BeanFactoryTransactionAttributeSourceAdvisor實(shí)例注入到代理對(duì)象中。

其中【aop實(shí)現(xiàn)原理分析】知道在AopUtils#findAdvisorsThatCanApply中判斷切面是否適用當(dāng)前bean,可以在這個(gè)地方斷點(diǎn)分析調(diào)用堆棧,AopUtils#findAdvisorsThatCanApply一致調(diào)用,最終通過(guò)以下代碼判斷是否適用切點(diǎn)。

AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Method method, Class<?> targetClass) 

這里可以根據(jù)參數(shù)打上條件斷點(diǎn)進(jìn)行調(diào)試分析調(diào)用棧,targetClass就是目標(biāo)class

…一系列調(diào)用 最終

SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
@Override
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
    //這里就是分析Method是否被@Transactional注解標(biāo)注,有的話,不用說(shuō)BeanFactoryTransactionAttributeSourceAdvisor適配當(dāng)前bean,進(jìn)行代理,并且注入切點(diǎn)
    //BeanFactoryTransactionAttributeSourceAdvisor
   AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
   if (attributes != null) {
      return parseTransactionAnnotation(attributes);
   }
   else {
      return null;
   }
}

上面就是判斷是否需要根據(jù)@Transactional進(jìn)行代理對(duì)象創(chuàng)建的判斷過(guò)程。@Transactional的作用一個(gè)就是標(biāo)識(shí)方法需要被代理,一個(gè)就是攜帶事務(wù)管理需要的一些屬性信息。

動(dòng)態(tài)代理邏輯實(shí)現(xiàn)

【aop實(shí)現(xiàn)原理分析】中知道,aop最終的代理對(duì)象的代理方法是

DynamicAdvisedInterceptor#intercept 

所以我們可以在這個(gè)方法斷點(diǎn)分析代理邏輯。

@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);
      }
   }
}

通過(guò)分析

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)

返回的是TransactionInterceptor,利用TransactionInterceptor是如何實(shí)現(xiàn)代理邏輯調(diào)用的?跟蹤

new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

發(fā)現(xiàn)最終是調(diào)用TransactionInterceptor#invoke方法,并且把CglibMethodInvocation注入到invoke方法中,從上面可以看到CglibMethodInvocation是包裝了目標(biāo)對(duì)象的方法調(diào)用的所有必須信息,因此,在TransactionInterceptor#invoke里面也是可以調(diào)用目標(biāo)方法的,并且還可以實(shí)現(xiàn)類似@Around的邏輯,在目標(biāo)方法調(diào)用前后繼續(xù)注入一些其他邏輯,比如事務(wù)管理邏輯。

TransactionInterceptor–最終事務(wù)管理者

下面看代碼。

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();
		}
	});
}

繼續(xù)跟蹤invokeWithinTransaction,下面的代碼中其實(shí)就可以看出一些邏輯端倪,就是我們猜想的實(shí)現(xiàn)方式,事務(wù)管理。

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.
       //開(kāi)啟事務(wù)
      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.
          //方法調(diào)用
         retVal = invocation.proceedWithInvocation();
      }
      catch (Throwable ex) {
         // target invocation exception
   		//回滾事務(wù)
         completeTransactionAfterThrowing(txInfo, ex);
         throw ex;
      }
      finally {
         cleanupTransactionInfo(txInfo);
      }
       //提交事務(wù)
      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();
      }
   }
}

總結(jié)

最終可以總結(jié)一下整個(gè)流程,跟開(kāi)始的猜想對(duì)照。

在這里插入圖片描述

分析源碼后對(duì)照

在這里插入圖片描述

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 微服務(wù)中使用Maven BOM來(lái)管理你的版本依賴詳解

    微服務(wù)中使用Maven BOM來(lái)管理你的版本依賴詳解

    這篇文章主要介紹了微服務(wù)中使用Maven BOM來(lái)管理你的版本依賴,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • SpringBoot整合Mysql和Redis的詳細(xì)過(guò)程

    SpringBoot整合Mysql和Redis的詳細(xì)過(guò)程

    這篇文章主要介紹了SpringBoot整合Mysql和Redis的示例代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • springboot實(shí)現(xiàn)訪問(wèn)多個(gè)redis庫(kù)

    springboot實(shí)現(xiàn)訪問(wèn)多個(gè)redis庫(kù)

    這篇文章主要介紹了springboot實(shí)現(xiàn)訪問(wèn)多個(gè)redis庫(kù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • spring中的ObjectPostProcessor詳解

    spring中的ObjectPostProcessor詳解

    這篇文章主要介紹了spring中的ObjectPostProcessor詳解,Spring Security 的 Java 配置不會(huì)公開(kāi)其配置的每個(gè)對(duì)象的每個(gè)屬性,這簡(jiǎn)化了大多數(shù)用戶的配置,畢竟,如果每個(gè)屬性都公開(kāi),用戶可以使用標(biāo)準(zhǔn) bean 配置,需要的朋友可以參考下
    2024-01-01
  • SpringBoot項(xiàng)目熱部署的實(shí)現(xiàn)

    SpringBoot項(xiàng)目熱部署的實(shí)現(xiàn)

    SpringBoot項(xiàng)目熱部署是一種讓開(kāi)發(fā)人員在修改代碼后無(wú)需重啟應(yīng)用即可看到更改效果的技術(shù),通過(guò)使用SpringBoot的DevTools等工具,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-09-09
  • 服務(wù)器CPU高居不下,JAVA線程占用排查方式

    服務(wù)器CPU高居不下,JAVA線程占用排查方式

    這篇文章主要介紹了服務(wù)器CPU高居不下,JAVA線程占用排查方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之二叉堆

    Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之二叉堆

    二叉堆是一種特殊的堆,其實(shí)質(zhì)是完全二叉樹(shù)。二叉堆有兩種:最大堆和最小堆。最大堆是指父節(jié)點(diǎn)鍵值總是大于或等于任何一個(gè)子節(jié)點(diǎn)的鍵值。而最小堆恰恰相反,指的是父節(jié)點(diǎn)鍵值總是小于任何一個(gè)子節(jié)點(diǎn)的鍵值
    2022-02-02
  • java通過(guò)AES生成公鑰加密數(shù)據(jù)ECC加密公鑰

    java通過(guò)AES生成公鑰加密數(shù)據(jù)ECC加密公鑰

    這篇文章主要為大家介紹了java通過(guò)AES生成公鑰加密數(shù)據(jù)ECC加密公鑰實(shí)現(xiàn)案例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • MyBatis之關(guān)于動(dòng)態(tài)SQL解讀

    MyBatis之關(guān)于動(dòng)態(tài)SQL解讀

    這篇文章主要介紹了MyBatis之關(guān)于動(dòng)態(tài)SQL解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • SpringBoot整合Kaptcha實(shí)現(xiàn)圖形驗(yàn)證碼功能

    SpringBoot整合Kaptcha實(shí)現(xiàn)圖形驗(yàn)證碼功能

    這篇文章主要介紹了SpringBoot整合Kaptcha實(shí)現(xiàn)圖形驗(yàn)證碼功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09

最新評(píng)論