0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

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

Android編程精選 ? 來源:CSDN博客 ? 作者:一擼向北 ? 2021-10-13 09:20 ? 次閱讀

@Transactional注解簡介

@Transactional是spring中聲明式事務管理的注解配置方式,相信這個注解的作用大家都很清楚。@Transactional注解可以幫助我們把事務開啟、提交或者回滾的操作,通過aop的方式進行管理。

通過@Transactional注解就能讓spring為我們管理事務,免去了重復的事務管理邏輯,減少對業(yè)務代碼的侵入,使我們開發(fā)人員能夠專注于業(yè)務層面開發(fā)。

我們知道實現(xiàn)@Transactional原理是基于spring aop,aop又是動態(tài)代理模式的實現(xiàn),通過對源碼的閱讀,總結出下面的步驟來了解實際中,在spring 是如何利用aop來實現(xiàn)@Transactional的功能的。

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

首先,對于spring中aop實現(xiàn)原理有了解的話,應該知道想要對一個方法進行代理的話,肯定需要定義切點。在@Transactional的實現(xiàn)中,同樣如此,spring為我們定義了以 @Transactional 注解為植入點的切點,這樣才能知道@Transactional注解標注的方法需要被代理。

有了切面定義之后,在spring的bean的初始化過程中,就需要對實例化的bean進行代理,并且生成代理對象。

生成代理對象的代理邏輯中,進行方法調(diào)用時,需要先獲取切面邏輯,@Transactional注解的切面邏輯類似于@Around,在spring中是實現(xiàn)一種類似代理邏輯。

@Transactional作用

根據(jù)上面的原理猜想,下面簡單介紹每個步驟的源碼以進行驗證。

首先是@Transactional,作用是定義代理植入點。我們知道代理對象創(chuàng)建的通過BeanPostProcessor的實現(xiàn)類AnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInstantiation方法來實現(xiàn)個,如果需要進行代理,那么在這個方法就會返回一個代理對象給容器,同時判斷植入點也是在這個方法中。

那么下面開始分析,在配置好注解驅動方式的事務管理之后,spring會在ioc容器創(chuàng)建一個BeanFactoryTransactionAttributeSourceAdvisor實例,這個實例可以看作是一個切點,在判斷一個bean在初始化過程中是否需要創(chuàng)建代理對象,都需要驗證一次BeanFactoryTransactionAttributeSourceAdvisor是否是適用這個bean的切點。如果是,就需要創(chuàng)建代理對象,并且把BeanFactoryTransactionAttributeSourceAdvisor實例注入到代理對象中。

前文我們知道在AopUtils#findAdvisorsThatCanApply中判斷切面是否適用當前bean,可以在這個地方斷點分析調(diào)用堆棧,AopUtils#findAdvisorsThatCanApply一致調(diào)用,最終通過以下代碼判斷是否適用切點。

  • AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Method method, Class targetClass)這里可以根據(jù)參數(shù)打上條件斷點進行調(diào)試分析調(diào)用棧,targetClass就是目標class …一系列調(diào)用
  • 最終SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
@Override
publicTransactionAttributeparseTransactionAnnotation(AnnotatedElementae){
//這里就是分析Method是否被@Transactional注解標注,有的話,不用說BeanFactoryTransactionAttributeSourceAdvisor適配當前bean,進行代理,并且注入切點
//BeanFactoryTransactionAttributeSourceAdvisor
AnnotationAttributesattributes=AnnotatedElementUtils.getMergedAnnotationAttributes(ae,Transactional.class);
if(attributes!=null){
returnparseTransactionAnnotation(attributes);
}
else{
returnnull;
}
}

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

動態(tài)代理邏輯實現(xiàn)

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

  • DynamicAdvisedInterceptor#intercept

所以我們可以在這個方法斷點分析代理邏輯。往期的面試題,點擊查看

@Override
publicObjectintercept(Objectproxy,Methodmethod,Object[]args,MethodProxymethodProxy)throwsThrowable{
ObjectoldProxy=null;
booleansetProxyContext=false;
ClasstargetClass=null;
Objecttarget=null;
try{
if(this.advised.exposeProxy){
//Makeinvocationavailableifnecessary.
oldProxy=AopContext.setCurrentProxy(proxy);
setProxyContext=true;
}
//Maybenull.Getaslateaspossibletominimizethetimewe
//"own"thetarget,incaseitcomesfromapool...
target=getTarget();
if(target!=null){
targetClass=target.getClass();
}
//follow
Listchain=this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);
ObjectretVal;
//CheckwhetherweonlyhaveoneInvokerInterceptor:thatis,
//norealadvice,butjustreflectiveinvocationofthetarget.
if(chain.isEmpty()&&Modifier.isPublic(method.getModifiers())){
//WecanskipcreatingaMethodInvocation:justinvokethetargetdirectly.
//NotethatthefinalinvokermustbeanInvokerInterceptor,soweknow
//itdoesnothingbutareflectiveoperationonthetarget,andnohot
//swappingorfancyproxying.
Object[]argsToUse=AopProxyUtils.adaptArgumentsIfNecessary(method,args);
retVal=methodProxy.invoke(target,argsToUse);
}
else{
//Weneedtocreateamethodinvocation...
retVal=newCglibMethodInvocation(proxy,target,method,args,targetClass,chain,methodProxy).proceed();
}
retVal=processReturnType(proxy,target,method,retVal);
returnretVal;
}
finally{
if(target!=null){
releaseTarget(target);
}
if(setProxyContext){
//Restoreoldproxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

		

通過分析List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)返回的是TransactionInterceptor,利用TransactionInterceptor是如何實現(xiàn)代理邏輯調(diào)用的?

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

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

TransactionInterceptor–最終事務管理者

下面看代碼。

  • TransactionInterceptor#invoke
@Override
publicObjectinvoke(finalMethodInvocationinvocation)throwsThrowable{
//Workoutthetargetclass:maybe{@codenull}.
//TheTransactionAttributeSourceshouldbepassedthetargetclass
//aswellasthemethod,whichmaybefromaninterface.
ClasstargetClass=(invocation.getThis()!=null?AopUtils.getTargetClass(invocation.getThis()):null);

//AdapttoTransactionAspectSupport'sinvokeWithinTransaction...
returninvokeWithinTransaction(invocation.getMethod(),targetClass,newInvocationCallback(){
@Override
publicObjectproceedWithInvocation()throwsThrowable{
returninvocation.proceed();
}
});
}

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

protectedObjectinvokeWithinTransaction(Methodmethod,ClasstargetClass,finalInvocationCallbackinvocation)
throwsThrowable{

//Ifthetransactionattributeisnull,themethodisnon-transactional.
finalTransactionAttributetxAttr=getTransactionAttributeSource().getTransactionAttribute(method,targetClass);
finalPlatformTransactionManagertm=determineTransactionManager(txAttr);
finalStringjoinpointIdentification=methodIdentification(method,targetClass);

if(txAttr==null||!(tminstanceofCallbackPreferringPlatformTransactionManager)){
//StandardtransactiondemarcationwithgetTransactionandcommit/rollbackcalls.
//開啟事務
TransactionInfotxInfo=createTransactionIfNecessary(tm,txAttr,joinpointIdentification);
ObjectretVal=null;
try{
//Thisisanaroundadvice:Invokethenextinterceptorinthechain.
//Thiswillnormallyresultinatargetobjectbeinginvoked.
//方法調(diào)用
retVal=invocation.proceedWithInvocation();
}
catch(Throwableex){
//targetinvocationexception
//回滾事務
completeTransactionAfterThrowing(txInfo,ex);
throwex;
}
finally{
cleanupTransactionInfo(txInfo);
}
//提交事務
commitTransactionAfterReturning(txInfo);
returnretVal;
}

else{
//It'saCallbackPreferringPlatformTransactionManager:passaTransactionCallbackin.
try{
Objectresult=((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr,
newTransactionCallback(){
@Override
publicObjectdoInTransaction(TransactionStatusstatus){
TransactionInfotxInfo=prepareTransactionInfo(tm,txAttr,joinpointIdentification,status);
try{
returninvocation.proceedWithInvocation();
}
catch(Throwableex){
if(txAttr.rollbackOn(ex)){
//ARuntimeException:willleadtoarollback.
if(exinstanceofRuntimeException){
throw(RuntimeException)ex;
}
else{
thrownewThrowableHolderException(ex);
}
}
else{
//Anormalreturnvalue:willleadtoacommit.
returnnewThrowableHolder(ex);
}
}
finally{
cleanupTransactionInfo(txInfo);
}
}
});

//Checkresult:ItmightindicateaThrowabletorethrow.
if(resultinstanceofThrowableHolder){
throw((ThrowableHolder)result).getThrowable();
}
else{
returnresult;
}
}
catch(ThrowableHolderExceptionex){
throwex.getCause();
}
}
}

		

總結

最終可以總結一下整個流程,跟開始的猜想對照。

來源:blog.csdn.net/qq_20597727/article/details/84868035

責任編輯:haq
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 代碼
    +關注

    關注

    30

    文章

    4671

    瀏覽量

    67767
  • spring
    +關注

    關注

    0

    文章

    335

    瀏覽量

    14259

原文標題:Spring的@Transactional如何實現(xiàn)的(必考)

文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Spring事務傳播性的相關知識

    本文主要介紹了Spring事務傳播性的相關知識。
    的頭像 發(fā)表于 01-10 09:29 ?303次閱讀
    <b class='flag-5'>Spring</b><b class='flag-5'>事務</b>傳播性的相關知識

    Spring狀態(tài)機的實現(xiàn)原理和使用方法

    說起 Spring 狀態(tài)機,大家很容易聯(lián)想到這個狀態(tài)機和設計模式狀態(tài)模式的區(qū)別是啥呢?沒錯,Spring 狀態(tài)機就是狀態(tài)模式的一種實現(xiàn),在介紹 S
    的頭像 發(fā)表于 12-26 09:39 ?1710次閱讀
    <b class='flag-5'>Spring</b>狀態(tài)機的<b class='flag-5'>實現(xiàn)</b>原理和使用方法

    Spring事務失效的十種常見場景

    Spring聲明事務功能更是提供了極其方便的事務配置方式,配合Spring Boot的自動配
    的頭像 發(fā)表于 12-11 15:03 ?730次閱讀

    springcloud 分布事務解決方案實例

    么都執(zhí)行成功,要么都執(zhí)行失敗。本文將介紹如何使用Spring Cloud來實現(xiàn)分布事務。 在分布系統(tǒng)
    的頭像 發(fā)表于 12-03 16:32 ?927次閱讀

    Spring依賴注入的四種方式

    Spring框架,依賴注入是一種核心的概念和機制。通過依賴注入,我們可以讓對象之間的依賴關系更加松散,并且能夠方便地進行單元測試和模塊化開發(fā)。在Spring,有多種方式來
    的頭像 發(fā)表于 12-03 15:11 ?1470次閱讀

    springcloud分布事務解決方案

    Spring Cloud是一套用于構建分布系統(tǒng)的開源框架,它提供了一系列組件和工具,可以幫助開發(fā)人員快速構建和管理基于微服務架構的應用程序。在分布系統(tǒng)
    的頭像 發(fā)表于 11-16 11:03 ?1883次閱讀

    springcloud如何實現(xiàn)分布

    ,我們可以快速搭建分布系統(tǒng),并且靈活地進行伸縮和擴展。 要實現(xiàn)分布系統(tǒng),我們可以按照以下步驟來使用Spring Cloud: 服務注冊與發(fā)現(xiàn): 分布
    的頭像 發(fā)表于 11-16 11:01 ?562次閱讀

    spring分布框架有哪些

    Spring分布框架是一套基于Spring框架的解決方案,用于構建分布系統(tǒng)。它提供了一系列的組件和模塊,可以幫助開發(fā)人員輕松地構建可擴展、高可用、高性能的分布
    的頭像 發(fā)表于 11-16 10:58 ?650次閱讀

    MYSQL事務的底層原理詳解

    事務實現(xiàn)機制上,MySQL 采用的是 WAL:Write-ahead logging,預寫日志,機制來實現(xiàn)的。
    的頭像 發(fā)表于 11-15 10:10 ?476次閱讀
    MYSQL<b class='flag-5'>事務</b>的底層原理詳解

    事務性日志結構文件系統(tǒng)的設計及實現(xiàn)

    本文發(fā)表于FAST 2022,探討日志結構文件系統(tǒng)層面的事務支持。本文主要對F2FS進行了支持事務的修改,實現(xiàn)了支持ACID事務特性的文件系統(tǒng)層面支持。本文通過實驗測試了SQLite和
    的頭像 發(fā)表于 10-16 16:01 ?552次閱讀
    <b class='flag-5'>事務</b>性日志結構文件系統(tǒng)的設計及<b class='flag-5'>實現(xiàn)</b>

    Spring Boot 的設計目標

    什么是Spring Boot Spring Boot 是 Spring 開源組織下的一個子項目,也是 Spring 組件一站解決方案,主要
    的頭像 發(fā)表于 10-13 14:56 ?487次閱讀
    <b class='flag-5'>Spring</b> Boot 的設計目標

    Spring 的線程池應用

    我們在日常開發(fā),經(jīng)常跟多線程打交道,Spring 為我們提供了一個線程池方便我們開發(fā),它就是 ThreadPoolTaskExecutor ,接下來我們就來聊聊 Spring 的線程池吧
    的頭像 發(fā)表于 10-13 10:47 ?523次閱讀
    <b class='flag-5'>Spring</b> 的線程池應用

    spring事務失效的一些場景

    對于從事java開發(fā)工作的同學來說,spring事務肯定再熟悉不過了。 在某些業(yè)務場景下,如果一個請求,需要同時寫入多張表的數(shù)據(jù)。為了保證操作的原子性(要么同時成功,要么同時失敗),避免數(shù)據(jù)
    的頭像 發(fā)表于 10-08 14:27 ?381次閱讀
    <b class='flag-5'>spring</b><b class='flag-5'>事務</b>失效的一些場景

    Spring Boot如何實現(xiàn)異步任務

    Spring Boot 提供了多種方式來實現(xiàn)異步任務,這里介紹三種主要實現(xiàn)方式。 1、基于注解 @Async @Async 注解是 Spring 提供的一種輕量級異步方法
    的頭像 發(fā)表于 09-30 10:32 ?1136次閱讀

    kafka client在 spring如何實現(xiàn)

    認識了 spring-boot-starter ,今天不妨來看下如何寫一個 pulsar-spring-boot-starter 模塊。 目標 寫一個完整的類似 kafka-spring-boot-st
    的頭像 發(fā)表于 09-25 11:21 ?399次閱讀
    kafka client在 <b class='flag-5'>spring</b>如何<b class='flag-5'>實現(xiàn)</b>