Spring事務原理完全解析

Real_man發表於2019-02-19

事務是什麼?瞭解事務的原理嗎?說下Spring的事務原理,能自己實現Spring事務原理嗎?先自我檢測下這些知識掌握了嗎。那麼接下來一起看下與Spring相關的事務

概念

事務具有ACID特性。

是指作為單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。

Spring事務的底層依賴MySQL的事務,程式碼層面上利用AOP實現。MySQL的事務有隔離級別的概念,只有InnoDB有事務,並且實現方式是利用undo log和redo log。

AOP方面,有連線點,切點,增強,目標,織入。參考Spring AOP入門,Spring則是在程式碼層面執行事務的時候使用TransactionInceptor進行攔截,然後處理。

系統解析Spring事務原理文章:

程式碼

  1. 在AopConfigUtils可以看到具體會生成什麼型別的AutoProxyCreator,這幾個都是beanPostProcessor,在Bean建立之後對Bean的例項進行自定義處理。如果使用了@EnableTransactionManagement,經過一些配置這次生成的是InfrastructureAdvisorAutoProxyCreator,具體如何生成這個類的點進去@EnableTransactionManagement裡面即可。

Spring事務原理完全解析

EnableTransactionManagement
-> @Import(TransactionManagementConfigurationSelector.class)
-> return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
-> AutoProxyRegistrar.registerBeanDefinitions中
-> 建立InfrastructureAdvisorAutoProxyCreator
複製程式碼

Spring事務原理完全解析

  1. 在Bean的生命週期中,Bean建立完成呼叫建立InfrastructureAdvisorAutoProxyCreator.postProcessAfterInitialization方法。

    另外AbstractAutowireCapableBeanFactory.initializeBean方法也值得一看

    獲取Bean的Advice,如果有Advice(增強的話),建立bean的動態代理。建立動態代理都是Spring AOP做的事情了,根據設定就是建立JDK動態代理和CGLib代理了,我們專案預設都是使用CGLib動態代理(proxyTargetClass=true即可),只說下CGlib的動態代理,主要利用了Enhancer類

Spring事務原理完全解析

​ 這裡有Enhacer用法Cglib的使用方法(1)--Enhancer

​ 攔截介面intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)有我們根據條件進行是否要攔截的資料,根據引數就可以判斷。

  1. 可以跟進去DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice方法中看

    PointcutAdvisor為BeanFactoryTransactionAttributeSourceAdvisor
    MethodMatcher為TransactionAttributeSourcePointcut
    複製程式碼

Spring事務原理完全解析

得到的攔截器為事務攔截器,既然是事務攔截器,那麼可以跟上之前的分析了。

Spring事務原理分析

  1. 我們接著看為什麼獲取的攔截器是MethodInterceptor。在MethodMatcher.match中有AdvisorAdapter

Spring事務原理完全解析

而Advice是advisor中的,advisor是BeanFactoryTransactionAttributeSourceAdvisor

  • 一種在TransactionProxyFactoryBean中預設的TransactionIntercetor

Spring事務原理完全解析

  • 在預設的@EnableTransactionManagement註解中,將BeanFactoryTransactionAttributeSourceAdvisor的advice設定為TransactionIntercetor,這一步的註解生效,我們第一步就已經講過了。

Spring事務原理完全解析

  1. 方法是如何匹配的,TransactionAttributeSourcePointcut中matches方法,呼叫TransactionAttributeSource屬性判斷是否有method的屬性

Spring事務原理完全解析

然後呼叫computeTransactionAttribute(method, targetClass),判斷是否有事務屬性

AbstractFallbackTransactionAttributeSource.computeTransactionAttribute
--> AnnotationTransactionAttributeSource.determineTransactionAttribute 獲取方法屬性
--> 獲取到TransactionAttribute,然後返回
複製程式碼
  1. 到現在我們基本上解釋了,Spring的事務攔截器是如何生效的,攔截器什麼時候設定的,事務方法是如何匹配的。

事務不生效

  • private方法不會生效,JDK中必須是介面,介面中不可能有private方法,而私有方法子類無法方法,也不會生效
  • CGLib代理的時候,final方法不會生效,拋NullPointException
  • protect方法的話,預設是隻允許public方法。

Spring事務原理完全解析

最後一個就是在當前的bean中非事務方法呼叫事務方法為什麼不生效?

public int save(String name, int age) throws Exception {
        insert(name, age);
        return 1;
    }
    @Transactional
    public void insert(String name, int age){
        jdbcTemplate.update("insert into user(id,name,age)values(1,'"+name+"',"+age+")");
        jdbcTemplate.update("insert into user(id,name,age)values(2,'"+name+"',"+age+")");
        jdbcTemplate.update("insert into user(id,name,age)values(1,'"+name+"',"+age+")");
    }
複製程式碼

答:

經過最終驗證,得出如下結論:

如果先呼叫的save方法,在進行方法攔截的時候,方法攔截器首先獲取當前動態代理的物件所代理的原始物件。

Spring事務原理完全解析

比如FirstApp生成的動態代理名稱為FirstApp$CGlibxxx,這個時候通過getTarget獲取的物件即為FirstApp的例項。

接下來如果判斷當前的方法比如save方法沒有Advice(增強),則直接呼叫原物件的方法,即這個時候呼叫的是FirstApp.save方法。而不是FirstApp$CGLibxxx的save方法。可以跟程式碼。

最後

Spring事務這塊,如果認真看我寫的文章,相信你會收穫不少

參考

相關文章