【spring原始碼學習】spring的事務管理的原始碼解析

Love Lenka發表於2017-08-07

【一】spring事務管理
(1)spring的事務管理,是基於aop動態代理實現的。對目標物件生成代理物件,加入事務管理的核心攔截器==>org.springframework.transaction.interceptor.TransactionInterceptor。
===>spring事務管理的核心攔截器
===>需要配置的資料項:事務管理機制配置屬性的查詢類transactionAttributeSource,事務管理的核心處理器PlatformTransactionManager(如果能配置就配置,不能配置就從beanFactory中根據介面拿)

(2)實現事務管理需要配置事務管理處理器(事務處理的支援抽象封裝(獲取事務狀態,提交事務,迴歸事務),如下是spring事務管理器的基礎類。
==>org.springframework.transaction.PlatformTransactionManager
==>org.springframework.transaction.support.AbstractPlatformTransactionManager

(3)獲取將要執行的方法的事務策略的配置資訊的查詢器。
==>org.springframework.transaction.interceptor.TransactionAttributeSource
==>org.springframework.transaction.annotation.AnnotationTransactionAttributeSource(基於註解進行事務管理配置的屬性獲取器)
==>該類內部也做屬性配置快取。以要執行的方法的物件Method method,和要執行的bean的Class<?> targetClass組裝成org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.DefaultCacheKey.該類重寫了equals和hashCode方法。


(4)spring事務管理的配置屬性的實體類
==>org.springframework.transaction.interceptor.TransactionAttribute
==>org.springframework.transaction.interceptor.DefaultTransactionAttribute(spring的預設)
==>org.springframework.transaction.interceptor.RuleBasedTransactionAttribute(基於註解的事務管理配置屬性的類)
==>其實就是,事務的傳播機制,事務回滾策略等配置資訊


(5)spring事務管理的一個FactoryBean
==>org.springframework.transaction.interceptor.TransactionProxyFactoryBean
==>內部初始化TransactionInterceptor,配置項:可以配置事務管理攔截器增強之外的別的攔截器,需要進行事務管理的的target, 進行事務管理的目標的介面proxyInterfaces
==>該類內部會呼叫afterPropertiesSet()方法,對目標target類生成一個代理物件。最終返回給業務使用。



【二】事務管理攔截器的執行過程TransactionInterceptor的invoke(final MethodInvocation invocation)方法
(1)獲取要進行事務管理的業務類的class的類物件
(2)根據類物件class和要執行的方法的method物件,基於事務管理配置屬性查詢器獲取事務機制的屬性TransactionAttribute
(3)根據事務配置機制的屬性獲取事務管理的處理器PlatformTransactionManager
(4)根據類物件class和要執行的方法method物件獲取事務管理,連線點標識joinpointIdentification(類的全路徑+執行方法的名字)
(5)根據事務管理處理器PlatformTransactionManager,事務機制配置屬性TransactionAttribute,事務連線點標識joinpointIdentification獲取當前事務資訊TransactionInfo
(6)繼續執行下一個攔截器或目標業務管理bean的方法
(7)根據(6)的執行結果進行相應的事務操作
(8)如果(6)沒有丟擲異常,則先根據TransactionInfo進行相關資源的清理,然後根據TransactionInfo進行事務提交操作
(9)如果(6)丟擲異常,則根據TransactionInfo進行事務回滾操作

 

【三】以xml配置方式進行事務管理的初始化原理解析
(1)    以下配置是事務管理機制屬性配置

   <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="doReweight" propagation="REQUIRES_NEW"/>
            <tx:method name="doClear*" propagation="REQUIRES_NEW"/>
            <tx:method name="doSend*" propagation="REQUIRES_NEW"/>
            <tx:method name="doBatchSave*" propagation="REQUIRES_NEW"/>

            <!--hibernate4必須配置為開啟事務 否則 getCurrentSession()獲取不到-->
            <tx:method name="get*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="count*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="find*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="list*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <aop:config expose-proxy="true" proxy-target-class="true">
        <!-- 只對業務邏輯層實施事務 -->
        <aop:pointcut id="txPointcut" expression="execution(* com.mobile.thinks..service..*+.*(..))"/>
        <aop:advisor id="txAdvisor" advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
View Code

(2)   在spring的IOC階段是用org.springframework.transaction.config.TxNamespaceHandler進行解析該<tx:advice>配置,呼叫解析器org.springframework.transaction.config.TxAdviceBeanDefinitionParser
==>如果沒有attributes的配置,則預設的配置屬性查詢器為org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
==>如果attributes的配置大於1個。報錯
==>如果attributes的配置等於1個。
   >則解析 <tx:method>的配置。併為每一個method的配置形成一個org.springframework.transaction.interceptor.RuleBasedTransactionAttribute的物件。如果有迴歸策略則形成org.springframework.transaction.interceptor.RollbackRuleAttribute配置。將所有的method配置形成ManagedMap<TypedStringValue, RuleBasedTransactionAttribute> transactionAttributeMap集合
  >解析完method後,則想IOC注入事務屬性配置查詢器為org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource.將method解析後的transactionAttributeMap的集合賦值給其屬性nameMap
==>想builder解析上下文註冊了兩個屬性transactionAttributeSource(事務管理機制屬性的查詢器),transactionManager(事務管理的處理器)
==>解析tx的配置,最終形成的advisor是org.springframework.transaction.interceptor.TransactionInterceptor.其依賴了剛才解析的事務管理機制屬性查詢器transactionAttributeSource,和事務管理處理器transactionManager

(3)在spring的IOC階段用的是org.springframework.aop.config.AopNamespaceHandler進行解析 <aop:config >該配置。呼叫的解析器為org.springframework.aop.config.ConfigBeanDefinitionParser

==>預設會向IOC容器中註冊bean實力化的前後置處理器org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator(BeanPostProcessor介面實現類)
==>解析<aop:advisor>是向IOC容器中註冊org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor.並建立txAdvice和txPointcut的依賴關係
==>解析<aop:pointcut>是向IOC容器中註冊org.springframework.aop.aspectj.AspectJExpressionPointcut

 

=====================================================分割線========================================================

*****spring事務管理是基於對資料庫連結的管理。以下所涉及的類,都是對資料庫DataSource的直接管理,從而對資料庫連結Connection的間接管理從而隱式進行資料庫事務管理******

【一】org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
==>該類對DataSource進行動態代理,但返回的代理物件是Connection.具體的操作見TransactionAwareInvocationHandler的invoke方法。
==>在對資料庫做任何操作的時候,都在invoke方法中。


【二】org.springframework.jdbc.datasource.TransactionAwareInvocationHandler
==>該類屬性targetDataSource引用的是真正的DataSource實現。
==>該類屬性target引用的是由 DataSourceUtils類透過targetDataSource獲取的一個資料庫連結,該連結與當前執行緒進行繫結。
==>在事務管理過程中Connection做的任何操作,都是代理物件進行操作的。都會呼叫該類的invoke方法,透過該方法對當前執行緒的事務管理進行繫結解綁等等操作。


【三】org.springframework.jdbc.datasource.DataSourceUtils
==>該類是從DataSource獲取資料庫連結,並結合Spring的TransactionSynchronizationManager類進行事務管理的相關操作
==>主要有獲取Connection,釋放Connection等相關操作。


【四】org.springframework.transaction.support.TransactionSynchronizationManager
==>對當前執行緒或當前事務的一些操作進行管理的操作類
==>可以在當前事務中註冊一些事件執行。TransactionSynchronization介面的實現類

【五】org.springframework.transaction.support.TransactionSynchronization
==>該類定義一些事務處理過程中的一些事件處理回撥方法。
==>例子:org.activiti.spring.TransactionSynchronizationAdapter
==>org.activiti.spring.SpringTransactionContext

 

(1)一個小案例,當事務提交後釋出非同步事件進行相應操作。如果事務未提交,回滾。則不釋出該事件

public static void publishEvent(final ApplicationEvent event) {
        if (TransactionSynchronizationManager.isActualTransactionActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    applicationContext.publishEvent(event);
                    super.afterCommit();
                }
                
            });
        } else {
            applicationContext.publishEvent(event);
        }
    }
View Code

 (2)測試執行緒保管箱,用於說明TransactionSynchronizationManager屬性中不同的執行緒保管箱的宣告,是用於記錄不同執行緒的事務管理的資訊的儲存。各個執行緒的事務資訊是互不干擾和影響的。

import org.springframework.core.NamedThreadLocal;
/**
 * 程式碼測試結果:
 * 主執行緒的數值==>【我是主執行緒】
 * 非主執行緒的數值====>【我是副執行緒】
 * 10秒後被喚醒。。。。。。
 * 主執行緒第二次獲取===>【我是主執行緒】
 * 
 * @author sxf
 *
 */
public class TestThreadLocal {
    
    
    public static void main(String[] args) {
        
        //在主執行緒宣告一個ThreadLocal的執行緒保管箱,用於管理不同執行緒儲存的不同的數值。看是否會執行緒間干擾
        final ThreadLocal<String> named=new NamedThreadLocal<String>("sxf test");
        
        //主執行緒設定數值
        named.set("【我是主執行緒】");
        //讀取主執行緒存取的數值
        System.out.println("主執行緒的數值==>"+named.get());
        
        
        //啟動一個新的執行緒,也使用主執行緒宣告的執行緒保管箱
        Thread aThread=new Thread(){

            @Override
            public void run() {
                //副執行緒設定數值
                named.set("【我是副執行緒】");
                //讀取副執行緒的儲存的數值
                String falg=named.get();
                System.out.println("非主執行緒的數值====>"+falg);
            }
            
        };
        aThread.start();
        //主執行緒休眠10妙,待副執行緒執行完畢,再次從ThreadLocal裡讀取數值,看是否被副執行緒覆蓋
        try {
            Thread.sleep(10000L);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("10秒後被喚醒。。。。。。");
        System.out.println("主執行緒第二次獲取===>"+named.get());
        
        
    }

}
View Code

 

相關文章