1. 程式人生 > >楊老師課堂之springAOP事務控制原始碼解析

楊老師課堂之springAOP事務控制原始碼解析

spring AOP基於動態代理實現,想看懂原始碼必須瞭解動態代理和位元組碼增強方面的知識。

基於對spring各種配置的瞭解,首先我們先從DataSourse由誰來管理入手。瞭解AOP。

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

接下來會將datasource交給各種連線池的操作類,如:ibatis、jdbcTemplate等等,這些不是我們關心的重點,我們需要關心的是dataSource是誰來管理了,在spring中配置了給一個DataSourceTransactionManager的物件:

  1. <beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  2.     <propertyname="dataSource">
  3.      <refbean="dataSource"/>
  4.     </property>
  5. </bean>

ok,先記錄下來,至於下面的NameMatchTransactionAttributeSource描述了那些情況要進行事務管理,我們將它理解為一種屬性配置,在執行時需要解析即可,所以他也並不是我們特別需要的重點。

接下里看看:TransactionInterceptor,它看起來有點像攔截器了,他將transactionManager包裝進去了;

  1. <beanid="txInterceptor"class="org.springframework.transaction.interceptor.TransactionInterceptor">
  2.   <propertyname="transactionManager">
  3.     <refbean="transactionManager"/>
  4.   </property>
  5.   <propertyname
    ="transactionAttributeSource">
  6.     <refbean="txAttributes"/>
  7.   </property>
  8. </bean>

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

一起來簡單看看TransactionInterceptor吧:


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

跟蹤進去看看:


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

也就是跟蹤到你set的那個TranscationManager裡頭去了,PlatformTransactionManager有多個實現類,注意選擇自己實現的那部分:本程式中叫:DataSourceTransactionManager,跟蹤進去看看getTransaction方法

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

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

2、部分如果發現事務物件獲取到就直接返回

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


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

將connection做了一個setAutoCommit(false);非自動提交模式,接下來就要看如何和框架結合起來了,如何讓呼叫的時候使用到這個connection,呼叫方如何知道使用這個connection;

看另外兩個紅色的部分:

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

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

  1. TransactionSynchronizationManager.bindResource(getDatasource() , txObject.getConnectionHolder());  

這樣一個操作,可見:TransactionSynchronizationManager提供了一個靜態方法getDatasource(),看名稱是繫結的意思,那麼繫結什麼呢?我們跟蹤進去看看:


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

看看resouces是什麼:


ThreadLocal,對了,就是它了,有關ThreadLocal的原理和細節,我這不想多提,也不是這裡的重點,這裡明確的就是,雖然它是全域性的一個靜態屬性,不過他是執行緒安全的,不論是get還是set還是remove。

我們知道這個connection被繫結到當前執行的執行緒中了,接下來只需要在使用時從這個裡面獲取出來即可。

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


可以看到,它果然是從這裡來獲取儲存到當前執行緒的connection。

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

他內部有啥道理所在:


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

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


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


接下來的就不用多說了吧,回到剛才的程式碼,不論是doGetConnection還是doReleaseConnection內部都會呼叫

  1. TransactionSynchronizationManager.getResource(datasouce)  

來獲取當前執行緒的connection。

當然各種連線操作物件也會有自己的transaction操作,他們也會去做setAutoCommit等相應的操作。不過最外層設定後,getConnection方法保證後,內部的操作幾乎就可以跳過了。