1. 程式人生 > >Spring事物原理完全解析

Spring事物原理完全解析

tint man cap after cti 既然 dap nsa 操作

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

  概念

  事務具有ACID特性。

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

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

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

  代碼

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

  

技術分享圖片

  EnableTransactionManagement

  - @Import(TransactionManagementConfigurationSelector.class)

  - return new String[] {AutoProxyRegistrar.class.getName(),

  ProxyTransactionManagementConfiguration.class.getName()};

  - AutoProxyRegistrar.registerBeanDefinitions中

  - 創建InfrastructureAdvisorAutoProxyCreator

  

技術分享圖片

  在Bean的生命周期中,Bean創建完成調用創建InfrastructureAdvisorAutoProxyCreator.postProcessAfterInitialization方法。

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

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

  

技術分享圖片

   這裏有Enhacer用法Cglib的使用方法(1)–Enhancer

  

   攔截接口intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)有我們根據條件進行是否要攔截的數據,根據參數就可以判斷。

  

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

  PointcutAdvisor為BeanFactoryTransactionAttributeSourceAdvisor

  MethodMatcher為TransactionAttributeSourcePointcut

  

技術分享圖片

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

  Spring事務原理分析

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

  

技術分享圖片

  而Advice是advisor中的,advisor是BeanFactoryTransactionAttributeSourceAdvisor

  一種在TransactionProxyFactoryBean中默認的TransactionIntercetor

  

技術分享圖片

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

  

技術分享圖片

  方法是如何匹配的,TransactionAttributeSourcePointcut中matches方法,調用TransactionAttributeSource屬性判斷是否有method的屬性

  

技術分享圖片

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

  AbstractFallbackTransactionAttributeSource.computeTransactionAttribute

  -- AnnotationTransactionAttributeSource.determineTransactionAttribute 獲取方法屬性

  -- 獲取到TransactionAttribute,然後返回

  到現在我們基本上解釋了,Spring的事務攔截器是如何生效的,攔截器什麽時候設置的,事務方法是如何匹配的。

  事務不生效

  private方法不會生效,JDK中必須是接口,接口中不可能有private方法,而私有方法子類無法方法,也不會生效

  CGLib代理的時候,final方法不會生效,拋NullPointException

  protect方法的話,默認是只允許public方法。

  

技術分享圖片

  最後一個就是在當前的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方法,在進行方法攔截的時候,方法攔截器首先獲取當前動態代理的對象所代理的原始對象。

  

技術分享圖片

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

  接下來如果判斷當前的方法比如save方法沒有Advice(增強),則直接調用原對象的方法,即這個時候調用的是FirstApp.save方法。而不是FirstApp$CGLibxxx的save方法。可以跟代碼。

  最後

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

?

Spring事物原理完全解析