SpringTransaction事務(wù)實(shí)現(xiàn)流程源碼解析_第1頁
SpringTransaction事務(wù)實(shí)現(xiàn)流程源碼解析_第2頁
SpringTransaction事務(wù)實(shí)現(xiàn)流程源碼解析_第3頁
SpringTransaction事務(wù)實(shí)現(xiàn)流程源碼解析_第4頁
SpringTransaction事務(wù)實(shí)現(xiàn)流程源碼解析_第5頁
已閱讀5頁,還剩12頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第SpringTransaction事務(wù)實(shí)現(xiàn)流程源碼解析目錄一、基于xml形式開啟Transaction1.創(chuàng)建數(shù)據(jù)庫user2.創(chuàng)建一個maven項(xiàng)目3.通過xml形式配置事務(wù)1)創(chuàng)建Spring命名空間2)開啟事務(wù)配置3)創(chuàng)建UserService類4.測試事務(wù)1)拋出RuntimeException2)注釋掉RuntimeException二、事務(wù)開啟入口TxNamespaceHandlerAnnotationDrivenBeanDefinitionParser三、AOP驅(qū)動事務(wù)TransactionInterceptor創(chuàng)建事務(wù)回滾事務(wù)

一、基于xml形式開啟Transaction

1.創(chuàng)建數(shù)據(jù)庫user

/*

NavicatPremiumDataTransfer

SourceServer:win-local

SourceServerType:MySQL

SourceServerVersion:50737

SourceHost:localhost:3306

SourceSchema:db0

TargetServerType:MySQL

TargetServerVersion:50737

FileEncoding:65001

Date:24/04/202520:27:41

SETNAMESutf8mb4;

SETFOREIGN_KEY_CHECKS=0;

------------------------------

--Tablestructureforuser

------------------------------

DROPTABLEIFEXISTS`user`;

CREATETABLE`user`(

`id`bigint(20)NOTNULLAUTO_INCREMENT,

`name`varchar(255)CHARACTERSETutf8mb4COLLATEutf8mb4_general_ciNULLDEFAULTNULL,

`age`int(11)NULLDEFAULTNULL,

PRIMARYKEY(`id`)USINGBTREE

)ENGINE=InnoDBAUTO_INCREMENT=1CHARACTERSET=utf8mb4COLLATE=utf8mb4_general_ciROW_FORMAT=Dynamic;

SETFOREIGN_KEY_CHECKS=1;

2.創(chuàng)建一個maven項(xiàng)目

不用Springboot依賴,引入mysql驅(qū)動依賴、spring-beans、spring-jdbc、Spring-context依賴

dependencies

dependency

groupIdmysql/groupId

artifactIdmysql-connector-java/artifactId

version5.1.46/version

/dependency

dependency

groupIdorg.springframework/groupId

artifactIdspring-beans/artifactId

version5.3.18/version

/dependency

!--springjdbc依賴spring-tx--

dependency

groupIdorg.springframework/groupId

artifactIdspring-jdbc/artifactId

version5.3.18/version

/dependency

dependency

groupIdmons/groupId

artifactIdcommons-dbcp2/artifactId

version2.7.0/version

/dependency

dependency

groupIdorg.springframework/groupId

artifactIdspring-context/artifactId

version5.3.18/version

/dependency

dependency

groupIdjunit/groupId

artifactIdjunit/artifactId

version4.13.2/version

/dependency

/dependencies

3.通過xml形式配置事務(wù)

1)創(chuàng)建Spring命名空間

首先在resources目錄下創(chuàng)建一個spring.xml文件,Spring框架為了聲明自己的Xml規(guī)范,在beans標(biāo)簽里定義了spring框架指定模塊的協(xié)議配置,我們可以通過Indexof/schema訪問spring框架的所有模塊包,各模塊包含了不同版本的xsd文件。

點(diǎn)擊進(jìn)入context目錄,查看xsd文件:

比如我要通過xml的形式配置一個bean,需要在beans標(biāo)簽中聲明xmln的值為:

/schema/beans

如果我想用spring的context模塊,那么需要聲明

xmlns:context=/schema/context

同時在xsi:schemeLocation里添加context的url和spring-contxt.xsd的url:

/schema/context

/schema/context/spring-context.xsd

例如我創(chuàng)建一個能在xml中使用spring-beans模塊,spring-txt模塊,spring-context模塊的配置如下:

xmlversion="1.0"encoding="UTF-8"

beansxmlns="/schema/beans"

xmlns:xsi="/2001/XMLSchema-instance"

xmlns:context="/schema/context"

xmlns:tx="/schema/tx"

xsi:schemaLocation="

/schema/beans/schema/beans/spring-beans.xsd

/schema/context/schema/context/spring-context.xsd

/schema/tx/schema/tx/spring-tx.xsd

/beans

如果沒有在beans標(biāo)簽里聲明協(xié)議,那么在配置bean時會出現(xiàn)找不到指定標(biāo)簽的問題。

2)開啟事務(wù)配置

在spring.xml文件中添加配置事務(wù)配置,使用annotation-driven屬性開啟事務(wù)啟動,

tx:annotation-driventransaction-manager="transactionManager"proxy-target-mode="proxy"/

proxy-target-class默認(rèn)為false,mode默認(rèn)模式為proxy,可不用配置,待會從源碼角度分析不同模式的事務(wù)開啟。

接著配置transactionManager,指定>

tx:annotation-driventransaction-manager="transactionManager"proxy-target-mode="proxy"/

beanid="transactionManager"

propertyname="dataSource"ref="ds"/

/bean

DataSourceTransactionManager里包含了DataSource屬性配置:

因此我們需要接著配置數(shù)據(jù)源bean別名為

beanid="ds"destroy-method="close"

propertyname="driverClassName"value="com.mysql.jdbc.Driver"/

propertyname="username"value="root"/

propertyname="password"value="root"/

propertyname="url"value="jdbc:mysql://localhost:3306/db0useSSL=false"/

propertyname="initialSize"value="5"/

propertyname="maxIdle"value="2"/

propertyname="maxTotal"value="100"/

/bean

接著給Service配置一個bean,引用dataSource數(shù)據(jù)源。

!--配置bean,指定數(shù)據(jù)源--

beanid="userService"

propertyname="dataSource"ref="ds"/

/bean

3)創(chuàng)建UserService類

通過dataSoucebean注入JDBCTemplate,添加一個update(intid,Stringname)方法,類上添加@Transactional(propagation=Propagation.REQUIRED)。

packageservice;

importorg.springframework.jdbc.core.JdbcTemplate;

importorg.springframework.transaction.annotation.Propagation;

importorg.springframework.transaction.annotation.Transactional;

importjavax.sql.DataSource;

@Transactional(propagation=Propagation.REQUIRED)

publicclassUserService{

privateJdbcTemplatejdbcTemplate;

publicvoidsetDataSource(DataSourcedataSource){

this.jdbcTemplate=newJdbcTemplate(dataSource);

publicStringgetUserName(intid){

returnjdbcTemplate.query("select*fromdb0.userwhereid=",rs-rs.next()rs.getString(2):"",newObject[]{id});

publicvoidupdateUser(intid,Stringname){

jdbcTemplate.update("updateusersetname=whereid=",newObject[]{name,id});

//thrownewRuntimeException("error!");

}

4.測試事務(wù)

使用ClassPathXmlApplicationContext類加載spring.xml文件

importorg.junit.Test;

importorg.springframework.context.ApplicationContext;

importorg.springframework.context.support.ClassPathXmlApplicationContext;

importservice.UserService;

publicclassUserServiceTests{

@Test

publicvoidtestTransaction(){

ApplicationContextcontext=newClassPathXmlApplicationContext("spring.xml");

UserServiceuserService=context.getBean("userService",UserService.class);

Stringname=userService.getUserName(1);

System.out.println("名字:"+name);

userService.updateUser(1,"bing");

StringupdateName=userService.getUserName(1);

System.out.println("更新后的名字:"+updateName);

}

數(shù)據(jù)庫一條記錄:

1)拋出RuntimeException

update方法里放開//thrownewRuntimeException(error!注釋,執(zhí)行后

數(shù)據(jù)庫里的記錄沒有修改,@Tranasctional注解生效。

2)注釋掉RuntimeException

重新執(zhí)行后,觀察結(jié)果

數(shù)據(jù)庫也更新過來了。

前面的篇幅從xml的配置形式解釋了Transaction集成過程,為什么要從xml形式入手transaction,是為了后面閱讀Spring-tx源碼做準(zhǔn)備。

二、事務(wù)開啟入口TxNamespaceHandler

根據(jù)spring.xml文件里配置的tx:annitation-driven關(guān)鍵字在Spring框架里全局搜索,找到目標(biāo)類TxNamespaceHandler。位于spring-tx模塊中的org.springframework.transaction.config包下。

/*

*Copyright2002-2012theoriginalauthororauthors.

*LicensedundertheApacheLicense,Version2.0(the"License");

*youmaynotusethisfileexceptincompliancewiththeLicense.

*YoumayobtainacopyoftheLicenseat

*/licenses/LICENSE-2.0

*Unlessrequiredbyapplicablelaworagreedtoinwriting,software

*distributedundertheLicenseisdistributedonan"ASIS"BASIS,

*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.

*SeetheLicenseforthespecificlanguagegoverningpermissionsand

*limitationsundertheLicense.

packageorg.springframework.transaction.config;

importorg.w3c.dom.Element;

importorg.springframework.beans.factory.xml.NamespaceHandlerSupport;

*{@codeNamespaceHandler}allowingfortheconfigurationof

*declarativetransactionmanagementusingeitherXMLorusingannotations.

*pThisnamespacehandleristhecentralpieceoffunctionalityinthe

*Springtransactionmanagementfacilitiesandofferstwoapproaches

*todeclarativelymanagetransactions.

*pOneapproachusestransactionsemanticsdefinedinXMLusingthe

*{@codetx:advice}elements,theotherusesannotations

*incombinationwiththe{@codetx:annotation-driven}element.

*BothapproachedaredetailedtogreatextentintheSpringreferencemanual.

*@authorRobHarrop

*@authorJuergenHoeller

*@since2.0

publicclassTxNamespaceHandlerextendsNamespaceHandlerSupport{

staticfinalStringTRANSACTION_MANAGER_ATTRIBUTE="transaction-manager";

staticfinalStringDEFAULT_TRANSACTION_MANAGER_BEAN_NAME="transactionManager";

staticStringgetTransactionManagerName(Elementelement){

return(element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE)

element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE):DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);

@Override

publicvoidinit(){

registerBeanDefinitionParser("advice",newTxAdviceBeanDefinitionParser());

//注冊事務(wù)

registerBeanDefinitionParser("annotation-driven",newAnnotationDrivenBeanDefinitionParser());

registerBeanDefinitionParser("jta-transaction-manager",newJtaTransactionManagerBeanDefinitionParser());

}

找到了annotation-driven,這個地方創(chuàng)建了一個AnnotationDrivenBeanDefinitionParser實(shí)例。

AnnotationDrivenBeanDefinitionParser

AnnotationDrivenBeanDefinitionParser類的作用是解析spring.xml里的配置tx:annotation-driven標(biāo)簽,并根據(jù)配置的mode選擇不同的模式取創(chuàng)建Transaction的整個初始化流程,此處也就是整個架Transaction架構(gòu)的開始地方。

Spring事務(wù)注冊的模式為動態(tài)代理模式,具體實(shí)現(xiàn)有2種:aspectj和proxy,可通過配置來選擇使用那種形式的事務(wù)注冊,如果不配置mode那么使用默認(rèn)的proxy形式創(chuàng)建,如果我們要使用aspectj模式開啟事務(wù),那么就配置mode=aspectj。

tx:annotation-driventransaction-manager="transactionManager"mode="aspectj"

我們可以看到Spring事務(wù)的開啟是默認(rèn)是以AOP為基礎(chǔ)的。

三、AOP驅(qū)動事務(wù)

AopAutoProxyConfigurer的configureAutoProxyCreator方法注冊了3個Bean,該3個Bean是驅(qū)動Spring事務(wù)架構(gòu)的核心支柱,分別是TransactionAttributeSource、TransactionInterceptor、TransactionAttributeSourceAdvisor。

privatestaticclassAopAutoProxyConfigurer{

publicstaticvoidconfigureAutoProxyCreator(Elementelement,ParserContextparserContext){

AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext,element);

StringtxAdvisorBeanName=TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;

if(!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)){

ObjecteleSource=parserContext.extractSource(element);

//CreatetheTransactionAttributeSourcedefinition.

RootBeanDefinitionsourceDef=newRootBeanDefinition(

"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");

sourceDef.setSource(eleSource);

sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

StringsourceName=parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

//CreatetheTransactionInterceptordefinition.

RootBeanDefinitioninterceptorDef=newRootBeanDefinition(TransactionInterceptor.class);

interceptorDef.setSource(eleSource);

interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

registerTransactionManager(element,interceptorDef);

interceptorDef.getPropertyValues().add("transactionAttributeSource",newRuntimeBeanReference(sourceName));

StringinterceptorName=parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

//CreatetheTransactionAttributeSourceAdvisordefinition.

RootBeanDefinitionadvisorDef=newRootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);

advisorDef.setSource(eleSource);

advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

advisorDef.getPropertyValues().add("transactionAttributeSource",newRuntimeBeanReference(sourceName));

advisorDef.getPropertyValues().add("adviceBeanName",interceptorName);

if(element.hasAttribute("order")){

advisorDef.getPropertyValues().add("order",element.getAttribute("order"));

//事務(wù)通知器transactionadvisor,基于AOP實(shí)現(xiàn)的advisor

parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName,advisorDef);

CompositeComponentDefinitioncompositeDef=newCompositeComponentDefinition(element.getTagName(),eleSource);

compositeDef.addNestedComponent(newBeanComponentDefinition(sourceDef,sourceName));

compositeDef.addNestedComponent(newBeanComponentDefinition(interceptorDef,interceptorName));

compositeDef.addNestedComponent(newBeanComponentDefinition(advisorDef,txAdvisorBeanName));

parserContext.registerComponent(compositeDef);

}

其中TransactionInterceptor是Spring事務(wù)的目標(biāo)方法的增強(qiáng),通過代理完成Spring事務(wù)的提交、異常處理和回滾。

TransactionInterceptor

TransactionInterceptor是Spring事務(wù)對目標(biāo)方法的增強(qiáng)器,說簡單點(diǎn)就是一層代理,基于Aop實(shí)現(xiàn),實(shí)現(xiàn)了spring-aop的Advice接口,同時實(shí)現(xiàn)了IntializingBean和BeanFactoryAware接口,只要有事務(wù)的執(zhí)行,那么目標(biāo)方法的調(diào)用類在invoke()方法會生成一個代理對象,通過invoke()方法對目標(biāo)調(diào)用方法進(jìn)行增強(qiáng)。

@FunctionalInterface

publicinterfaceMethodInterceptorextendsInterceptor{

*Implementthismethodtoperformextratreatmentsbeforeand

*aftertheinvocation.Politeimplementationswouldcertainly

*liketoinvoke{@linkJoinpoint#proceed()}.

*@paraminvocationthemethodinvocationjoinpoint

*@returntheresultofthecallto{@linkJoinpoint#proceed()};

*mightbeinterceptedbytheinterceptor

*@throwsThrowableiftheinterceptorsorthetargetobject

*throwsanexception

Objectinvoke(MethodInvocationinvocation)throwsThrowable;

}

TransactionInterceptor的invoke()實(shí)現(xiàn):

@Override

@Nullable

publicObjectinvoke(finalMethodInvocationinvocation)throwsThrowable{

//Workoutthetargetclass:maybe{@codenull}.

//TheTransactionAttributeSourceshouldbepassedthetargetclass

//aswellasthemethod,whichmaybefromaninterface.

ClasstargetClass=(invocation.getThis()!=nullAopUtils.getTargetClass(invocation.getThis())

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論