




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第@TransactionalEventListener的使用和實現(xiàn)原理分析AFTER_ROLLBACK,
//指定目標方法在事務(wù)完成時執(zhí)行,這里的完成是指無論事務(wù)是成功提交還是事務(wù)回滾了
AFTER_COMPLETION
四、代碼示例
這里主要是為了講解如何使用@TransactionalEventListener,所以就不列出所有代碼了。
@Data
publicclassUser{
privatelongid;
privateStringname;
privateIntegerage;
業(yè)務(wù)實現(xiàn):
@Service
@Slf4j
publicclassUserServiceImplextendsimplementsUserService{
@Autowired
UserMapperuserMapper;
@Autowired
ApplicationEventPublishereventPublisher;
publicvoiduserRegister(Useruser){
userMapper.insertUser(user);
eventPublisher.publishEvent(newUserRegisterEvent(newDate()));
自定義事件:
@Getter
@Setter
publicclassUserRegisterEventextendsApplicationEvent{
privateDateregisterDate;
publicUserRegisterEvent(DateregisterDate){
super(registerDate);
this.registerDate=registerDate;
事件監(jiān)聽器:
@Slf4j
@Component
publicclassUserListener{
@Autowired
UserServiceuserService;
@Async
@TransactionalEventListener(phase=TransactionPhase.AFTER_COMMIT,classes=UserRegisterEvent.class)
publicvoidonUserRegisterEvent(UserRegisterEventevent){
userService.sendActivationCode(event.getRegisterDate());
五、實現(xiàn)原理
關(guān)于事務(wù)的實現(xiàn)原理,這里其實是比較簡單的,Spring對事務(wù)監(jiān)控的處理邏輯在TransactionSynchronization中,如下是該接口的聲明:
publicinterfaceTransactionSynchronizationextendsFlushable{
//在當前事務(wù)掛起時執(zhí)行
defaultvoidsuspend(){
//在當前事務(wù)重新加載時執(zhí)行
defaultvoidresume(){
//在當前數(shù)據(jù)刷新到數(shù)據(jù)庫時執(zhí)行
defaultvoidflush(){
//在當前事務(wù)commit之前執(zhí)行
defaultvoidbeforeCommit(booleanreadOnly){
//在當前事務(wù)completion之前執(zhí)行
defaultvoidbeforeCompletion(){
//在當前事務(wù)commit之后實質(zhì)性
defaultvoidafterCommit(){
//在當前事務(wù)completion之后執(zhí)行
defaultvoidafterCompletion(intstatus){
很明顯,這里的TransactionSynchronization接口只是抽象了一些行為,用于事務(wù)事件發(fā)生時觸發(fā),這些行為在Spring事務(wù)中提供了內(nèi)在支持,即在相應(yīng)的事務(wù)事件時,其會獲取當前所有注冊的TransactionSynchronization對象,然后調(diào)用其相應(yīng)的方法。
那么這里TransactionSynchronization對象的注冊點對于我們了解事務(wù)事件觸發(fā)有至關(guān)重要的作用了。
這里我們首先回到事務(wù)標簽的解析處,在前面講解事務(wù)標簽解析時,我們講到Spring會注冊一個TransactionalEventListenerFactory類型的bean到Spring容器中,這里關(guān)于標簽的解析讀者可以閱讀本人前面的文章Spring事務(wù)用法示例與實現(xiàn)原理。
這里注冊的TransactionalEventListenerFactory實現(xiàn)了EventListenerFactory接口,這個接口的主要作用是先判斷目標方法是否是某個監(jiān)聽器的類型,然后為目標方法生成一個監(jiān)聽器,其會在某個bean初始化之后由Spring調(diào)用其方法用于生成監(jiān)聽器。如下是該類的實現(xiàn):
publicclassTransactionalEventListenerFactoryimplementsEventListenerFactory,Ordered{
//指定當前監(jiān)聽器的順序
privateintorder=50;
publicvoidsetOrder(intorder){
this.order=order;
@Override
publicintgetOrder(){
returnthis.order;
//指定目標方法是否是所支持的監(jiān)聽器的類型,這里的判斷邏輯就是如果目標方法上包含有
//TransactionalEventListener注解,則說明其是一個事務(wù)事件監(jiān)聽器
@Override
publicbooleansupportsMethod(Methodmethod){
return(AnnotationUtils.findAnnotation(method,TransactionalEventListener.class)!=null);
//為目標方法生成一個事務(wù)事件監(jiān)聽器,這里ApplicationListenerMethodTransactionalAdapter實現(xiàn)了
//ApplicationEvent接口
@Override
publicApplicationListenercreateApplicationListener(StringbeanName,Classtype,Methodmethod){
returnnewApplicationListenerMethodTransactionalAdapter(beanName,type,method);
這里關(guān)于事務(wù)事件監(jiān)聽的邏輯其實已經(jīng)比較清楚了。
ApplicationListenerMethodTransactionalAdapter本質(zhì)上是實現(xiàn)了ApplicationListener接口的,也就是說,其是Spring的一個事件監(jiān)聽器,這也就是為什么進行事務(wù)處理時需要使用ApplicationEventPublisher.publish()方法發(fā)布一下當前事務(wù)的事件。
ApplicationListenerMethodTransactionalAdapter在監(jiān)聽到發(fā)布的事件之后會生成一個TransactionSynchronization對象,并且將該對象注冊到當前事務(wù)邏輯中,如下是監(jiān)聽事務(wù)事件的處理邏輯:
@Override
publicvoidonApplicationEvent(ApplicationEventevent){
//如果當前TransactionManager已經(jīng)配置開啟事務(wù)事件監(jiān)聽,
//此時才會注冊TransactionSynchronization對象
if(TransactionSynchronizationManager.isSynchronizationActive()){
//通過當前事務(wù)事件發(fā)布的參數(shù),創(chuàng)建一個TransactionSynchronization對象
TransactionSynchronizationtransactionSynchronization=
createTransactionSynchronization(event);
//注冊TransactionSynchronization對象到TransactionManager中
TransactionSynchronizationManager
.registerSynchronization(transactionSynchronization);
}elseif(this.annotation.fallbackExecution()){
//如果當前TransactionManager沒有開啟事務(wù)事件處理,但是當前事務(wù)監(jiān)聽方法中配置了
//fallbackExecution屬性為true,說明其需要對當前事務(wù)事件進行監(jiān)聽,無論其是否有事務(wù)
if(this.annotation.phase()==TransactionPhase.AFTER_ROLLBACK
logger.isWarnEnabled()){
logger.warn("Processing"
+event+"asafallbackexecutiononAFTER_ROLLBACKphase");
processEvent(event);
}else{
//走到這里說明當前是不需要事務(wù)事件處理的,因而直接略過
if(logger.isDebugEnabled()){
logger.debug("Notransactionisactive-skipping"+event);
}
這里需要說明的是,上述annotation屬性就是在事務(wù)監(jiān)聽方法上解析的TransactionalEventListener注解中配置的屬性。
可以看到,對于事務(wù)事件的處理,這里創(chuàng)建了一個TransactionSynchronization對象,其實主要的處理邏輯就是在返回的這個對象中,而createTransactionSynchronization()方法內(nèi)部只是創(chuàng)建了一個TransactionSynchronizationEventAdapter對象就返回了。
這里我們直接看該對象的源碼:
privatestaticclassTransactionSynchronizationEventAdapter
extendsTransactionSynchronizationAdapter{
privatefinalApplicationListenerMethodAdapterlistener;
privatefinalApplicationEventevent;
privatefinalTransactionPhasephase;
publicTransactionSynchronizationEventAdapter(ApplicationListenerMethodAdapter
listener,ApplicationEventevent,TransactionPhasephase){
this.listener=listener;
this.event=event;
this.phase=phase;
@Override
publicintgetOrder(){
returnthis.listener.getOrder();
//在目標方法配置的phase屬性為BEFORE_COMMIT時,處理beforecommit事件
publicvoidbeforeCommit(booleanreadOnly){
if(this.phase==TransactionPhase.BEFORE_COMMIT){
processEvent();
//這里對于aftercompletion事件的處理,雖然分為了三個if分支,但是實際上都是執(zhí)行的processEvent()
//方法,因為aftercompletion事件是事務(wù)事件中一定會執(zhí)行的,因而這里對于commit,
//rollback和completion事件都在當前方法中處理也是沒問題的
publicvoidafterCompletion(intstatus){
if(this.phase==TransactionPhase.AFTER_COMMITstatus==STATUS_COMMITTED){
processEvent();
}elseif(this.phase==TransactionPhase.AFTER_ROLLBACK
status==STATUS_ROLLED_BACK){
processEvent();
}elseif(this.phase==TransactionPhase.AFTER_COMPLETION){
processEvent();
//執(zhí)行事務(wù)事件
protectedvoidprocessEvent(){
cessEvent(this.event);
可以看到,對于事務(wù)事件的處理,最終都是委托給了ApplicationListenerMethodAcessEvent()方法進行的。如下是該方法的源碼:
publicvoidprocessEvent(ApplicationEventevent){
//處理事務(wù)事件的相關(guān)參數(shù),這里主要是判斷TransactionalEventListener注解中是否配置了value
//或classes屬性,如果配置了,則將方法參數(shù)轉(zhuǎn)換為該指定類型傳給監(jiān)聽的方法;如果沒有配置,則判斷
//目標方法是ApplicationEvent類型還是PayloadApplicationEvent類型,是則轉(zhuǎn)換為該類型傳入
Object[]args=resolveArguments(event);
//這里主要是獲取TransactionalEventListener注解中的condition屬性,然后通過
//Springexpressionlanguage將其與目標類和方法進行匹配
if(shouldHandle(event,args)){
//通過處理得到的參數(shù)借助于反射調(diào)用事務(wù)監(jiān)聽方法
Objectresult=doInvoke(args);
if(result!=null){
//對方法的返回值進行處理
handleResult(result);
}else{
logger.trace("Noresultobjectgiven-noresulttohandle");
//處理事務(wù)監(jiān)聽方法的參數(shù)
protectedObject[]resolveArguments(ApplicationEventevent){
//獲取發(fā)布事務(wù)事件時傳入的參數(shù)類型
ResolvableTypedeclaredEventType=getResolvableType(event);
if(declaredEventType==null){
returnnull;
//如果事務(wù)監(jiān)聽方法的參數(shù)個數(shù)為0,則直接返回
if(this.method.getParameterCount()==0){
returnnewObject[0];
//如果事務(wù)監(jiān)聽方法的參數(shù)不為ApplicationEvent或PayloadApplicationEvent,則直接將發(fā)布事務(wù)
//事件時傳入的參數(shù)當做事務(wù)監(jiān)聽方法的參數(shù)傳入。從這里可以看出,如果事務(wù)監(jiān)聽方法的參數(shù)不是
//ApplicationEvent或PayloadApplicationEvent類型,那么其參數(shù)必須只能有一個,并且這個
//參數(shù)必須與發(fā)布事務(wù)事件時傳入的參數(shù)一致
ClasseventClass=declaredEventType.getRawClass();
if((eventClass==null||!ApplicationEvent.class.isAssignableFrom(eventClass))
eventinstanceofPayloadApplicationEvent){
returnnewObject[]{((PayloadApplicationEvent)event).getPayload()};
}else{
//如果參數(shù)類型為ApplicationEvent或PayloadApplicationEvent,則直接將其傳入事務(wù)事件方法
returnnewObject[]{event};
//判斷事務(wù)事件方法方法是否需要進行事務(wù)事件處理
privatebooleanshouldHandle(ApplicationEventevent,@NullableObject[]args){
if(args==null){
returnfalse;
Stringcondition=getCondition();
if(StringUtils.hasText(condition)){
Assert.notNull(this.evaluator,"EventExpressionEvaluatormustnobenull");
EvaluationContextevaluationContext=this.evaluator.createEvaluationContext(
event,this.targetClass,this.method,args,this.applicationContext);
returnthis.evaluator.con
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 健康促進教學(xué)課件
- 天宮課堂互動活動方案
- T/ZHCA 102-2020體重控制人群用營養(yǎng)代餐食品
- 我的媽媽課件分享
- 2025遼陽職業(yè)技術(shù)學(xué)院輔導(dǎo)員考試試題及答案
- 2025蘇州幼兒師范高等??茖W(xué)校輔導(dǎo)員考試試題及答案
- 2025甘肅交通職業(yè)技術(shù)學(xué)院輔導(dǎo)員考試試題及答案
- 網(wǎng)絡(luò)工程畢業(yè)設(shè)計
- 創(chuàng)意寫作考試試卷及答案2025年
- 第七講-氣流干燥系統(tǒng)設(shè)計特點
- 錨桿(土釘)鉆孔施工記錄
- 水陸兩用挖掘機安全操作保養(yǎng)規(guī)程
- 橡塑保溫管施工方案
- 人力資源管理學(xué)習(xí)通章節(jié)答案期末考試題庫2023年
- 貴州省醫(yī)療服務(wù)項目收費標準
- 病原學(xué)標本采集與送檢規(guī)范
- 黑河學(xué)院輔導(dǎo)員考試題庫
- 抖音運營工作計劃模版(3篇)
- 顯微鏡望遠鏡的設(shè)計與組裝
- 中石油職稱英語通用教材
評論
0/150
提交評論