fescar是gts剛開源的版本,對gts關注已久,比較熟悉其原理,而半年前本身又開發了一個可用版本meepo(詳情),因此對fescar的源碼也是必看。經過比較,能夠看meepo設計上的不足,以及一些編碼細節上的困惑。javascript
項目架構及環境搭建很少敘述,github官網已經夠詳細了,直接開始擼源碼。java
demo的使用上,和meepo大致一致,在須要分佈式事務的方法上,加上事務註解便可。git
很普通的dubbo程序,再看下purchase方法github
和meepo惟一不一樣的是,fescar使用了自定義註解@GlobalTransactional,meepo則是spring事務註解@Transactional。spring
自定義註解表明了fescar棄用了JTA規範,本身承擔TM的角色,好處是加入分佈式事務後,不會影響到原來的事務實現。meepo默認會修改@Transactional標註的原單機事務實現,雖然不影響使用,但不算合理,能夠手動指定transmanager解決,如@Transactional(數組
)。壞處則是放棄了spring 已經實現了的成熟穩定JTA規範。如今問題來了,一樣實現事務,一樣用的註解,二者實現機制同樣嗎?先說答案,是同樣的。本篇文章在講解@GlobalTransactional註解的同時,也過了一遍spring的@Transactional。緩存
先跟蹤代碼,在第一張圖的的purchase處,打了一個斷點,debug到時,發現service是cglib生成的一個代理。第一個問題來了,爲何是cglib?spring的常識是,aop有接口的bean默認jdk動態代理,沒接口的cglib代理,或者xml配置 proxy-target-class="true" 強制使用cglib。可是在本例中,bussinesService有接口,xml未配置,卻爲什麼使用cglib代理?
架構
ok,這個問題一會再找找,咱們得先解決另一個重要的問題,代理類是何時生成的?
框架
這個問題好解答,就是BeanPostProcessor接口。fescar、dubbo不少框架包括spring自己,都有使用BeanPostProcessor來爲xml中配置的bean生成代理,我寫的meepo也有,這是spring很常見的一種擴展使用方式。分佈式
看一下spirng的生命週期。
在xml裏配置的每個bean,在初始化的先後,會先找到緩存的BeanPostProcessor list,自己做爲參數,傳入BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法,爲bean作一些處理如生成代理類,而後返回。
fercas的GlobalTransactionScanner承擔了這個角色,GlobalTransactionScanner繼承了spring aop包下的AbstractAutoProxyCreator類,這個類實現了InstantiationBeanPostProcessor接口,是spring實現aop最關鍵的一個抽象類,相似JTA事務裏的AbstractPlatformTransactionManager。
默認狀況下,代理是經過AbstractAutoProxyCreator中的postProcessAfterInitialization()建立的。
上述方法的執行邏輯爲:
a.獲取緩存的bean名字,getCacheKey()方法其實是便於子類擴展。默認返回className_beanName
b.若earlyProxyReferences緩存中不包含當前cacheKey,則調用wrapIfNecessary()建立代理對象。
earlyProxyReferences這個緩存是幹嗎的呢?
從上下文中能夠找到getEarlyBeanReference()方法中會將相應的cacheKey保存到earlyProxyReferences中,同時也會調用wrapIfNecessary()方法,所以能夠看出該緩存用於保存已經建立過代理對象的cachekey,避免重複建立。代碼以下:
那麼getEarlyBeanReference()方法又是什麼時候被調用的呢?
經過分析能夠看到,getEarlyBeanReference()方法在SmartInstantiantionAwareBeanPostProcessor中聲明,咱們知道,spring爲了解決單例bean之間的循環依賴問題,提早將代理對象暴露出去。
接下來是wrapIfNecessary方法,該方法是真正生成代理類的地方。GlobalTransactionScanner重寫了該方法,咱們來看一下。
主要邏輯有:
a. 查看當前bean是否有@GlobalTransactional註解,若是沒有,本身返回bean,再也不繼續生成代理。
b. new了 一個實現了MethodInterceptor接口的方法攔截器GlobalTransactionalInterceptor,相似jdk動態代理的InvocationHandler,關鍵邏輯所在
!AopUtils.isAopProxy(bean) 判斷是否已經是代理類,避免重複代理,若未被代理,則調用父類的wrapIfNecessary方法。
AbstractAutoProxyCreator是全部使用spring aop的關鍵類,和GlobalTransactionScanner同樣,spring自身的一些aop機制也使用了AbstractAutoProxyCreator。咱們看下@Transactional的使用,配置xml後在須要事務的方法加上註解便可,以下
<!-- 事務管理器配置,單數據源事務 -->
<bean id="pkgouTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="pkGouDataSource" />
</bean>
<!-- 使用annotation定義事務 -->
<tx:annotation-driven transaction-manager="pkgouTransactionManager" />
tx標籤初始化的時候,由對應的解析器AnnotationDrivenBeanDefinitionParser來解析,在解析方法parse中,會註冊一個InfrastructureAdvisorAutoProxyCreator類,這個類繼承了AbstractAutoProxyCreator。使用普通的aop標籤,解析時也會註冊一個繼承AbstractAutoProxyCreator的AspectJAwareAdvisorAutoProxyCreator類。類結構圖以下:
AbstractAutoProxyCreator這個抽象類,有一個惟一抽象方法getAdvicesAndAdvisorsForBean。該方法做用是爲bean獲取全部適用的Advice和Advisor。
Advice和Advisor以及PointCut都是aop都基礎概念,簡單理解下:
Advice 即通知,具體的處理邏輯,好比方法先後加日誌,具體實現能夠是MethodInterceptor的invoke方法;
PointCut 是要攔截的範圍,好比哪一個包下的controller;
Advisor是對Advice和PointCut的一個封裝,一個服務可能初始化了幾個Advisor,那麼bean初始化時,遍歷這些Advisor,先判斷本身是否在Advisor的PointCut範圍內,若是是,則生成aop代理。
AbstractAutoProxyCreator的類結構圖能夠看到,它有一個子類AbstractAdvisorAutoProxyCreator,同時是幾個標籤解析生成的Creator的父類,AbstractAdvisorAutoProxyCreator的做用是自動獲取Advisor集合,咱們來看下它的getAdvicesAndAdvisorsForBean方法。
findEligibleAdvisors處理兩件事
標籤解析的中間,動態生成一個Advisor
GlobalTransactionScanner並無繼承AbstractAdvisorAutoProxyCreator,由於fercas的註解並無在xml裏配置,也不須要自動找其餘Advisor,它只要處理本身的攔截器就行了,看一下它的getAdvicesAndAdvisorsForBean方法。
很簡單,就是返回了以前在wrap裏new的GlobalTransactionalInterceptor,GlobalTransactionalInterceptor實現MethodInterceptor,間接實現了Advice。繼續跟蹤wrap方法,獲取Advice和Advisor後,返回Object[](這裏是只有一個Advice)。接着把Object數組和bean,傳入到createProxy方法,生成代理類。
這裏關鍵是兩步:
buildAdvisors把Advice和Advisor的Object[] 混合物,處理後統一成Advisor[],放入new的一個ProxyFactory中,proxyFactory繼續生成代理類。
咱們看下buildAdvisors關鍵代碼
若是Object[]裏的元素是Advisor,直接返回,若是是Advice並且是MethodInterceptor,包裝成一個DefaultPointcutAdvisor,這個Advisor的構造方法,生成一個默認的TruePointcut,也就是前面提到的所有範圍。
繼續看proxyFactory.getProxy(getProxyClassLoader()) 這句,終於到了選擇代理的地方,咱們看下。
這裏傳入的config的屬性拷貝自GlobalTransactionScanner的屬性(點進方法能夠看到,不貼代碼了),當optimize或者ProxyTargetClass任一屬性是true的時候,會進入方法體,進一步判斷當前bean是不是接口,注意,這裏不是判斷是否實現接口,顯然,業務service是一個class,這時候,就會使用cglib來生成代理類。咱們來看下GlobalTransactionScanner構造方法。
終於能夠解答了前面的問題,爲何是cglib的代理類。和xml配置效果同樣,只要找到這個屬性配置的地方就行了,若是沒配,默認是false。
最後,動態代理的生成過程再也不敘述,代理類(jdk動態代理)執行業務接口方法的路徑是
$proxy.purchase -> InvocationHandler.invoke ->intercept.invoke
cglib代理類的路徑沒看,應該大致一致。
本篇主要講解了@GlobalTransactional 生成代理類的整個過程,其實和fercas框架關係不大,由於其原理和spring的@transactionanl註解基本同樣(@transactional詳解)
整理下咱們的思路,方法上的自定義註解,會爲方法所在的類生成aop代理,方法先後加上一些自定義邏輯,好比fescar的全局事務管理。生成代理的路徑以下:
GlobalTransactionScanner.postProcessAfterInitialization->GlobalTransactionScanner.wrapIfNecessary->AbstractAutoProxyCreator.wrapIfNecessary->GlobalTransactionScanner.getAdvicesAndAdvisorsForBean->AbstractAutoProxyCreator.createProxy->AbstractAutoProxyCreator.buildAdvisors->proxyFactory.getProxy
再總結一下,若是咱們想使用自定義註解生成AOP代理,須要哪些步驟: