2009-07-08 107 views
216

我想知道在使用@Transactional註解方法時實際發生了什麼? 當然,我知道Spring將在事務中包裝該方法。春天 - @Transactional - 在後臺發生了什麼?

不過,我有以下幾點疑惑:

  1. 聽說春天創建代理類?有人可以解釋這更多深度實際上駐留在該代理類中的是什麼?實際課堂會發生什麼?我怎麼能看到Spring的創建代理的類
  2. 我也看了在春天的文檔是:

注:由於這種機制是基於代理,只有「外部」方法調用通過進來代理將被攔截。這意味着即使被調用的方法被標記爲@Transactional,「自調用」(即調用目標對象的某個其他方法的目標對象內的方法)也不會導致實際的事務處理。

來源:http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

爲什麼只有外部方法調用將是下交易,而不是自我調用的方法呢?

+1

相關討論在這裏:http://stackoverflow.com/questions/3120143/where-should-i-put-transactional-annotation-at-an-interface-definition-or-at-an/3120323#3120323 – 2010-09-26 20:07:30

回答

168

這是一個很大的話題。 Spring參考文檔專門討論了多個章節。我建議閱讀Aspect-Oriented ProgrammingTransactions,因爲Spring的聲明式事務支持在其基礎上使用AOP。

但是在很高的層次上,Spring爲類聲明@Transactional關於類本身或成員的代理。代理在運行時大部分是不可見的。它爲Spring提供了一種方法,將方法調用之前,之後或周圍的行爲注入到被代理的對象中。事務管理只是可以掛鉤的行爲的一個例子。安全檢查是另一個例子。而且你也可以提供你自己的,例如日誌。因此,當您使用@Transactional註解方法時,Spring會動態創建一個代理,該代理實現與您註解的類相同的接口。當客戶端對你的對象進行調用時,攔截的調用和通過代理機制注入的行爲。

順便說一句,EJB中的事務工作也是類似的。

正如您所觀察到的,通過代理機制僅在來自某個外部對象的調用進行時才起作用。當您在對象內進行內部呼叫時,您確實通過繞過代理的「」參考進行呼叫。但是,有些方法可以解決這個問題。我解釋了this forum post中的一種方法,其中我使用BeanFactoryPostProcessor在運行時將代理實例注入「自引用」類。我將此引用保存到名爲「me」的成員變量中。然後,如果我需要進行需要更改線索的交易狀態的內部呼叫,我通過代理指示呼叫(例如「me.someMethod()」)。)論壇帖子更詳細地解釋。請注意,BeanFactoryPostProcessor代碼現在有點不同了,因爲它是在Spring 1.x時間框架中重寫的。但希望它給你一個想法。我有可能提供的更新版本。

+1

>>代理大多在運行時不可見 哦!我很好奇,看到他們:)休息..你的答案是非常全面的。這是你第二次幫助我..感謝所有的幫助。 – peakit 2009-07-08 17:37:36

+9

沒問題。如果您逐步使用調試器,您可以看到代理代碼。這可能是最簡單的方法。沒有魔法;他們只是Spring包中的類。 – 2009-07-08 17:47:47

139

當Spring加載你的bean定義並且被配置爲查找@Transactional註解時,它會在你的實際bean周圍創建這些代理對象。這些代理對象是在運行時自動生成的類的實例。當一個方法被調用時,這些代理對象的默認行爲就是調用「target」bean(即你的bean)上的相同方法。

但是,代理服務器也可以提供攔截器,並且當它們出現時,這些攔截器將在調用目標bean的方法之前由代理服務器調用。對於使用@Transactional註釋的目標bean,Spring將創建一個TransactionInterceptor,並將其傳遞給生成的代理對象。所以當你從客戶端代碼中調用方法時,你需要調用代理對象的方法,該方法首先調用TransactionInterceptor(它開始一個事務),然後調用目標Bean的方法。當調用完成時,TransactionInterceptor提交/回滾事務。它對客戶端代碼透明。至於「外部方法」的東西,如果你的bean調用它自己的方法之一,那麼它不會通過代理來做到這一點。記住,Spring將bean包裝在代理中,bean不知道它。只有來自「外部」的bean的調用纔會通過代理。

這有幫助嗎?

20

作爲一個視覺人物,我喜歡用代理模式的順序圖來衡量。如果你不知道如何閱讀箭頭,我讀了這樣的第一個:Client執行Proxy.method()

  1. 客戶端調用上從他的角度目標的方法,以及被默默地由代理
  2. 如果前方面被定義截獲,代理將執行它
  3. 然後,實際方法(目標)被執行
  4. 之後的返回和投擲後是可選的方面是 該方法返回之後,執行和/或如果該方法將引發 異常
  5. 之後,代理執行方面後(如果被定義)
  6. 最後代理返回到調用客戶端

Proxy Pattern Sequence Diagram (我被允許張貼在我提到它的起源狀態的照片。作者:Noel Vaes,網址:www.noelvaes.eu)

0

最簡單的答案是,您聲明的任何方法@Transactional事務的邊界開始,邊界在方法完成時結束。

如果您正在使用JPA調用,那麼所有提交都在此事務邊界中。假設你正在保存entity1,entity2和entity3。現在,在保存entity3時會發生異常,因爲enitiy1和entity2進入同一事務,因此entity1和entity2將與entity3一起回滾。

交易:(entity1.save,entity2.save,entity3.save)。任何異常都會導致所有JPA事務與數據庫的回滾。 Spring內部使用JPA內部事務。