【SEATA源碼分析】spring 模塊源碼解析

一. 導讀

spring是java開發必備框架,類一般都是通過spring進行管理。那spring之外的框架,尤其是想使用spring代理的類的框架,如何藉助spring的擴展點來操作bean?
這篇文章主要分析 Seata 如何藉助 spring擴展點 對代理的bean進行操作,生成Seata想要的數據庫代理類和對 被全局事務註解的bean 織入不同事務模式對應的 advisor 實現類。

二. Spring模塊主要類解析

在這裏插入圖片描述
這兒是spring模塊的目錄,類的主要功能:
@GlobalTransactional :註解在業務方法上用來開啓全局事務,可以自定義超時時間、全局事務的名字、回滾時調用的類等。
@GlobalLock :聲明事務僅執行在本地RM中,但是本次事務確保在更新狀態下的操作記錄不會被其他全局事務操作。即將本地事務的執行納入seata分佈式事務的管理,一起競爭全局鎖,保證全局事務在執行的時候,本地業務不可以操作全局事務中的記錄。
GlobalTransactionalInterceptor: 實現了spring的 MethondInterceptor,聲明一個環繞通知。攔截器主要就是判斷是否有上面兩個註解,並調用相應處理方法。
MethodDesc: 持有方法和方法上全局事務註解,model類。
TccActionInterceptor: 是 TCC 模式下獨有的方法攔截器,也實現了 spring 的MethondInterceptor

三. 環繞通知(攔截器)分析

目前的seata版本有兩種 Advisor,一個是GlobalTransactionalInterceptor,一個是TccActionInterceptor
GlobalTranscationInterceptor是在scanner檢測到不是TCC模式下的bean,並且方法上有@GlobalTransactional註解或者@GlobalLock註解才織入的。
TccActionInterceptor是當scanner檢測到bean的父類接口中有@LocalTCC註解,才織入的。

GlobalTransactionalInterceptor 攔截器有三個成員變量:TransactionnalTemplateGlobalLockTemplateFailureHandler,分別處理有全局事務註解的方法、和全局鎖註解的方法和失敗的情況。
在這裏插入圖片描述
攔截器invoke()方法主要邏輯是根據註解的類型找到對應的模板進行執行,用到了模板模式,具體模板的邏輯其他模塊進行解析。

四. 全局事務掃描類分析

GlobalTransactionalScanner中,通過利用spring的擴展點,對bean進行自己想要的處理。

這個類繼承了 AbstractAutoProxyCreator並實現了三個類InitializingBeanApplicationContextAwareDisposableBean

實現的類主要是爲了獲取spring的上下文 ApplicationContext 和在實例化完成時進行 TM 、RM的初始化,並註冊銷燬時調用的鉤子,比較簡單。這裏有一個可以優化的地方,就是當項目中沒有掃描到存在@GlobalTransactional註解的方法時,可以不用進行TM的初始化。

重點在繼承AbstractAutoProxyCreate,繼承這個類,獲得了兩次操作bean的機會。
第一次通過使用 postProcessAfterInitialization(),在bean被創建後,屬性注入之前,對bean進行處理。
在這裏插入圖片描述
這裏主要就是對 bean類型爲爲DataSource子類的時候,進行bean的代理,把原有的DataSource對象換成自己想要的DataSourceProxy對象。這裏可能會被重複調用,所以多了一個判斷,如果被代理過了,則交給父類處理。

wrapIfNecessary()的調用時機是在postProcessAfterInitialization()之後
在這裏插入圖片描述
主要就是獲取bean的類型,根據bean的類型來實例化對應的adsivor。

這裏有一個問題,被遠程調用的方法沒有註解,如何納入全局事務?
猜測:在進行遠程調用的時候,帶上了事務id,遠程業務模塊攔截器通過事務id生成本地事務。答案要在後續的源碼解析中獲得,這裏只是猜測。

在這裏插入圖片描述
這裏當不是aop代理的bean時,手動調用父類方法,父類會調用 getAdvicesAndAdvisorsForBean()來獲取上面實例化好的interceptor。如果是aop代理,就把實例化好的interceptor攔截器增加到Advisor[]數組中,放置在第一位。
spring在執行完 wrapIfNecessery()後,會繼續進行aop代理類的實例化。

五. 總結

Seata中的bean有三種:normalTccBean、localTccBean(被@LocalTcc註解)、normalBean(被@GlobalTransactional或者@GlobalLock註解),其中normalTccBean是不會被 wrap 的,其他兩個會被代理,通過wrapIfNecessery(),織入advisor。

更多好文請關注微信公衆號:我手一杯
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章