天天看點

spring事務管理器的源碼和了解

以前說了大多的原理,今天來說下spring的事務管理器的實作過程,順帶源碼幹貨帶上。

其實這個文章唯一的就是帶着看看代碼,但是前提你要懂得動态代理以及位元組碼增強方面的知識(http://blog.csdn.net/xieyuooo/article/details/7624146),關于annotation在文章:http://blog.csdn.net/xieyuooo/article/details/8002321

也有說明,是以本文也就帶着看看代碼而已。

關于annotation這裡就不說了,我們看看平時一般會怎麼樣來配置spring的配置,通過配置檔案反射源碼如何看看。

一般來講首先會配置一個datasource,至于你配置什麼連接配接池還是用jndi這裡就不提到細節,總之我們認為配置的spring的全局名稱為datasource就可以了。

接下來會将datasource交給各種連接配接池的操作類,如:ibatis、jdbctemplate等等,這些不是我們關心的重點,我們需要關心的是datasource是誰來管理了,在spring中配置了給一個datasourcetransactionmanager的對象:

ok,先記錄下來,至于下面的namematchtransactionattributesource描述了那些情況要進行事務管理,我們将它了解為一種屬性配置,在運作時需要解析即可,是以他也并不是我們特别需要的重點。

接下裡看看:transactioninterceptor,它看起來有點像攔截器了,他将transactionmanager包裝進去了;

這裡是一個點,再繼續看,beannameautoproxycreator,這個看名字就知道是自動代理的類了,并且包裝了transactioninterceptor的對象進去,也就是這個地方就是代理,然後會将事務的處理交給transactioninterceptor攔截器來完成,可能這個不是我們的重點,不過簡單看看也無妨,這個類細節代碼就不貼了,進去你會看到就是講攔截器包裝後,然後通過beanname設定哪些類需要被攔截,根據你的配置來完成,spring 後來基于annotation實作的就不是這樣,他會掃描類中的annotation來實作類似的功能。

一起來簡單看看transactioninterceptor吧:

spring事務管理器的源碼和了解

細節代碼太多,看關鍵代碼,紅色部分表示出來了,其實在aop調用中,我們比較關注invoke、intercept這類代碼關聯字的方法,因為proxy調用的就是他們,由他們自己去調用其他的方法,這裡invoke首先發現在事務下,首先調用了createtranscationifnecessary這個方法。

跟蹤進去看看:

spring事務管理器的源碼和了解

這裡看到開始擷取transactionmanager了,get方法沒啥好看的,配置檔案注入進去了,我們看看tm.gettranscation裡頭做了啥。

也就是跟蹤到你set的那個transcationmanager裡頭去了,platformtransactionmanager有多個實作類,注意選擇自己實作的那部分:本程式中叫:datasourcetransactionmanager,跟蹤進去看看gettransaction方法

spring事務管理器的源碼和了解

這個代理類,需要注意幾個加紅色的地方:

1、目前看來應該是獲事務的方法

2、部分如果發現事務對象擷取到就直接傳回

3、做一個dobegin的操作,這i類關鍵字一般是指切入時的預先操作,那麼閑看看這個dobegin幹啥了

spring事務管理器的源碼和了解

我們想要的東西來了,相信看到第二個紅色區域部分,大家都會很熟悉自己做事務是怎麼做的,發現spring也是這樣做的。

将connection做了一個setautocommit(false);非自動送出模式,接下來就要看如何和架構結合起來了,如何讓調用的時候使用到這個connection,調用方如何知道使用這個connection;

看另外兩個紅色的部分:

第一個紅色部分可以看出是擷取事務對象若為空(不是事務或已經是事務),則從datasource對象中擷取一個connection,包裝成一個handle,放入事務對象中(事務對象内部的包裝請自己去看下)。

而第三個額部分是,如果是一個新的connectionhandler(其實判定的是一些狀态,使用中,spring會修改handler的狀态,這也是為什麼spring要包裝一個handler了,因為需要自定義的很多狀态資訊);他執行了一個

這樣一個操作,可見:transactionsynchronizationmanager提供了一個靜态方法getdatasource(),看名稱是綁定的意思,那麼綁定什麼呢?我們跟蹤進去看看:

spring事務管理器的源碼和了解

咦,resouces貌似裡面有一個map,如果為空,就put一個進去,那麼resouce是個什麼東西呢?他會不會有線程沖突的問題?

看看resouces是什麼:

spring事務管理器的源碼和了解

threadlocal,對了,就是它了,有關threadlocal的原理和細節,我這不想多提,也不是這裡的重點,這裡明确的就是,雖然它是全局的一個靜态屬性,不過他是線程安全的,不論是get還是set還是remove。

我們知道這個connection被綁定到目前運作的線程中了,接下來隻需要在使用時從這個裡面擷取出來即可。

我們再回到上面看到的dotransaction方法還沒看細節,這裡來看看。

spring事務管理器的源碼和了解

可以看到,它果然是從這裡來擷取儲存到目前線程的connection。

貌似看得差不多了,好像少了一半,那一半,datasouces是各個廠家的,他們的各自的datasouce方法是自己的,getconnection内部有自己的算法,如何做到他們在getconnection的時候,執行相應的,這個時候,我們來看看一個攔截connection的方式:transactionawaredatasourceproxy,

他内部有啥道理所在:

spring事務管理器的源碼和了解

這裡可以看到使用了動态代理,擷取相應的datasouces,那麼就找到對應的代理類裡面去看看他的invoke方法是什麼:

transactionawareinvocationhandler裡面,可以跟蹤這個是一個内部類了,進去看看他的invoke方法:

spring事務管理器的源碼和了解

可以看到切入的位置,向上看到兩個紅色部分是要去擷取connection,我們跟蹤進去看看:

spring事務管理器的源碼和了解

接下來的就不用多說了吧,回到剛才的代碼,不論是dogetconnection還是doreleaseconnection内部都會調用

來擷取目前線程的connection。

當然各種連接配接操作對象也會有自己的transaction操作,他們也會去做setautocommit等相應的操作。不過最外層設定後,getconnection方法保證後,内部的操作幾乎就可以跳過了。