




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第@TransactionalEventListener的使用和實現原理分析AFTER_ROLLBACK,
//指定目標方法在事務完成時執行,這里的完成是指無論事務是成功提交還是事務回滾了
AFTER_COMPLETION
四、代碼示例
這里主要是為了講解如何使用@TransactionalEventListener,所以就不列出所有代碼了。
@Data
publicclassUser{
privatelongid;
privateStringname;
privateIntegerage;
業務實現:
@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;
事件監聽器:
@Slf4j
@Component
publicclassUserListener{
@Autowired
UserServiceuserService;
@Async
@TransactionalEventListener(phase=TransactionPhase.AFTER_COMMIT,classes=UserRegisterEvent.class)
publicvoidonUserRegisterEvent(UserRegisterEventevent){
userService.sendActivationCode(event.getRegisterDate());
五、實現原理
關于事務的實現原理,這里其實是比較簡單的,Spring對事務監控的處理邏輯在TransactionSynchronization中,如下是該接口的聲明:
publicinterfaceTransactionSynchronizationextendsFlushable{
//在當前事務掛起時執行
defaultvoidsuspend(){
//在當前事務重新加載時執行
defaultvoidresume(){
//在當前數據刷新到數據庫時執行
defaultvoidflush(){
//在當前事務commit之前執行
defaultvoidbeforeCommit(booleanreadOnly){
//在當前事務completion之前執行
defaultvoidbeforeCompletion(){
//在當前事務commit之后實質性
defaultvoidafterCommit(){
//在當前事務completion之后執行
defaultvoidafterCompletion(intstatus){
很明顯,這里的TransactionSynchronization接口只是抽象了一些行為,用于事務事件發生時觸發,這些行為在Spring事務中提供了內在支持,即在相應的事務事件時,其會獲取當前所有注冊的TransactionSynchronization對象,然后調用其相應的方法。
那么這里TransactionSynchronization對象的注冊點對于我們了解事務事件觸發有至關重要的作用了。
這里我們首先回到事務標簽的解析處,在前面講解事務標簽解析時,我們講到Spring會注冊一個TransactionalEventListenerFactory類型的bean到Spring容器中,這里關于標簽的解析讀者可以閱讀本人前面的文章Spring事務用法示例與實現原理。
這里注冊的TransactionalEventListenerFactory實現了EventListenerFactory接口,這個接口的主要作用是先判斷目標方法是否是某個監聽器的類型,然后為目標方法生成一個監聽器,其會在某個bean初始化之后由Spring調用其方法用于生成監聽器。如下是該類的實現:
publicclassTransactionalEventListenerFactoryimplementsEventListenerFactory,Ordered{
//指定當前監聽器的順序
privateintorder=50;
publicvoidsetOrder(intorder){
this.order=order;
@Override
publicintgetOrder(){
returnthis.order;
//指定目標方法是否是所支持的監聽器的類型,這里的判斷邏輯就是如果目標方法上包含有
//TransactionalEventListener注解,則說明其是一個事務事件監聽器
@Override
publicbooleansupportsMethod(Methodmethod){
return(AnnotationUtils.findAnnotation(method,TransactionalEventListener.class)!=null);
//為目標方法生成一個事務事件監聽器,這里ApplicationListenerMethodTransactionalAdapter實現了
//ApplicationEvent接口
@Override
publicApplicationListenercreateApplicationListener(StringbeanName,Classtype,Methodmethod){
returnnewApplicationListenerMethodTransactionalAdapter(beanName,type,method);
這里關于事務事件監聽的邏輯其實已經比較清楚了。
ApplicationListenerMethodTransactionalAdapter本質上是實現了ApplicationListener接口的,也就是說,其是Spring的一個事件監聽器,這也就是為什么進行事務處理時需要使用ApplicationEventPublisher.publish()方法發布一下當前事務的事件。
ApplicationListenerMethodTransactionalAdapter在監聽到發布的事件之后會生成一個TransactionSynchronization對象,并且將該對象注冊到當前事務邏輯中,如下是監聽事務事件的處理邏輯:
@Override
publicvoidonApplicationEvent(ApplicationEventevent){
//如果當前TransactionManager已經配置開啟事務事件監聽,
//此時才會注冊TransactionSynchronization對象
if(TransactionSynchronizationManager.isSynchronizationActive()){
//通過當前事務事件發布的參數,創建一個TransactionSynchronization對象
TransactionSynchronizationtransactionSynchronization=
createTransactionSynchronization(event);
//注冊TransactionSynchronization對象到TransactionManager中
TransactionSynchronizationManager
.registerSynchronization(transactionSynchronization);
}elseif(this.annotation.fallbackExecution()){
//如果當前TransactionManager沒有開啟事務事件處理,但是當前事務監聽方法中配置了
//fallbackExecution屬性為true,說明其需要對當前事務事件進行監聽,無論其是否有事務
if(this.annotation.phase()==TransactionPhase.AFTER_ROLLBACK
logger.isWarnEnabled()){
logger.warn("Processing"
+event+"asafallbackexecutiononAFTER_ROLLBACKphase");
processEvent(event);
}else{
//走到這里說明當前是不需要事務事件處理的,因而直接略過
if(logger.isDebugEnabled()){
logger.debug("Notransactionisactive-skipping"+event);
}
這里需要說明的是,上述annotation屬性就是在事務監聽方法上解析的TransactionalEventListener注解中配置的屬性。
可以看到,對于事務事件的處理,這里創建了一個TransactionSynchronization對象,其實主要的處理邏輯就是在返回的這個對象中,而createTransactionSynchronization()方法內部只是創建了一個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分支,但是實際上都是執行的processEvent()
//方法,因為aftercompletion事件是事務事件中一定會執行的,因而這里對于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();
//執行事務事件
protectedvoidprocessEvent(){
cessEvent(this.event);
可以看到,對于事務事件的處理,最終都是委托給了ApplicationListenerMethodAcessEvent()方法進行的。如下是該方法的源碼:
publicvoidprocessEvent(ApplicationEventevent){
//處理事務事件的相關參數,這里主要是判斷TransactionalEventListener注解中是否配置了value
//或classes屬性,如果配置了,則將方法參數轉換為該指定類型傳給監聽的方法;如果沒有配置,則判斷
//目標方法是ApplicationEvent類型還是PayloadApplicationEvent類型,是則轉換為該類型傳入
Object[]args=resolveArguments(event);
//這里主要是獲取TransactionalEventListener注解中的condition屬性,然后通過
//Springexpressionlanguage將其與目標類和方法進行匹配
if(shouldHandle(event,args)){
//通過處理得到的參數借助于反射調用事務監聽方法
Objectresult=doInvoke(args);
if(result!=null){
//對方法的返回值進行處理
handleResult(result);
}else{
logger.trace("Noresultobjectgiven-noresulttohandle");
//處理事務監聽方法的參數
protectedObject[]resolveArguments(ApplicationEventevent){
//獲取發布事務事件時傳入的參數類型
ResolvableTypedeclaredEventType=getResolvableType(event);
if(declaredEventType==null){
returnnull;
//如果事務監聽方法的參數個數為0,則直接返回
if(this.method.getParameterCount()==0){
returnnewObject[0];
//如果事務監聽方法的參數不為ApplicationEvent或PayloadApplicationEvent,則直接將發布事務
//事件時傳入的參數當做事務監聽方法的參數傳入。從這里可以看出,如果事務監聽方法的參數不是
//ApplicationEvent或PayloadApplicationEvent類型,那么其參數必須只能有一個,并且這個
//參數必須與發布事務事件時傳入的參數一致
ClasseventClass=declaredEventType.getRawClass();
if((eventClass==null||!ApplicationEvent.class.isAssignableFrom(eventClass))
eventinstanceofPayloadApplicationEvent){
returnnewObject[]{((PayloadApplicationEvent)event).getPayload()};
}else{
//如果參數類型為ApplicationEvent或PayloadApplicationEvent,則直接將其傳入事務事件方法
returnnewObject[]{event};
//判斷事務事件方法方法是否需要進行事務事件處理
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. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年中國男性護理液行業市場全景分析及前景機遇研判報告
- 中班美術活動變臉
- 無創呼吸機應用和護理
- 智慧教育發展
- 煤礦機電運輸事故原因及控制對策探究
- 物業品質管理與培訓
- 車用尿素研發生產與銷售合作協議書
- 房地產租賃合同補充協議書
- 員工培訓計劃表
- 知識產權侵權代理授權協議
- 公路水運工程施工企業主要負責人和安全生產管理人員考核大綱和模擬試題庫1
- 預應力混凝土管樁(L21G404)
- 企業法務概論智慧樹知到期末考試答案章節答案2024年溫州大學
- 第1課 多姿與多彩(生活色彩)課件-2023-2024學年高中美術人教版(2019)選擇性必修1《繪畫》
- 海拔高度與氣壓、空氣密度、重力加速度對照表
- 考評員職業道德課件
- 物控培訓教程預防呆滯料與庫存控制的實用方法
- 天氣數據分析與氣象預測
- 駕照體檢表完整版本
- 核醫學工作中輻射防護知識課件
- 審評茶培訓課件
評論
0/150
提交評論