2011-11-07 98 views
13

正如你多知道,當你代理的對象,當你爲春/ EJB創建事務屬性的bean或者甚至當你創建一些框架的部分模擬,該代理對象不知道,和內部通話都是這樣未進行重定向,再也不攔截...如何處理Spring/EJB/Mockito ...代理上的內部調用?

這就是爲什麼,如果你做這樣的事情在春天:

@Transactionnal 
public void doSomething() { 
    doSomethingInNewTransaction(); 
    doSomethingInNewTransaction(); 
    doSomethingInNewTransaction(); 
} 

@Transactional(propagation = Propagation.REQUIRES_NEW) 
public void doSomethingInNewTransaction() { 
    ... 
} 

當你調用DoSomething的,你希望有除主3個新的交易一個,但實際上,由於這個問題,你只能得到一個...


所以我不知道你怎麼做才能處理這些類型的問題...

我其實是在一個情況下,我必須處理複雜的交易系統,和我沒有看到比什麼更好的辦法把我的服務分成許多小服務,這樣我肯定能夠通過所有的代理...

困擾我很多,因爲所有的代碼屬於相同的功能域,不應該分裂...

我發現這個相關的問題有趣的答案: Spring - @Transactional - What happens in background?

羅布^ h說,我們可以注入裏面的服務春季代理,並調用proxy.doSomethingInNewTransaction();代替。 這是很容易做到,它的工作原理,但我真的不喜歡它...

雲峯侯這樣說:

所以,我寫我自己的CglibSubclassingInstantiationStrategy的版本和 代理創建者,這樣它將使用CGLIB來生成一個真實的子類 ,這個子類委託調用它的超級實例,而不是另一個實例,Spring現在正在這樣做。因此,我可以自由註釋任何方法(只要它不是私人的,只要 ),並且從我稱之爲這些方法的任何地方,他們將會照顧到它們 。那麼,我仍然有支付的代價:1.我必須列出 所有註釋,我希望啓用新的CGLIB子類 創建。 2.由於我現在是 生成子類,所以我不能在最終的方法上註釋,所以最終的方法不能被截取。

他對我們「這春現在正在做」是什麼意思?這是否意味着內部交易呼叫現在被攔截?


你認爲哪個更好?

你分割你的類時,你需要一些事務性的粒度? 或者您是否使用上述的一些解決方法? (請分享)

+0

沒有更多的想法?請確認您已經看到此問題 –

回答

15

我會談論Spring和@Transactional,但建議也適用於許多其他框架。

這是基於代理方面的固有問題。據這裏的春天文檔中討論:

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies

有多種可能的解決方案。

重構您的類以避免繞過代理的自調用調用。

Spring文檔將此描述爲「最好的方法(最好的術語在此處使用鬆散)」

這種方法的優點是它的簡單性,並且與任何框架都沒有關係。然而,對於一個非常繁瑣的代碼庫來說,這可能不合適,因爲你最終會得到許多微不足道的小類。

內部在類中獲取對代理的引用。

這可以通過注入代理或硬編碼的「AopContext.currentProxy()」調用來完成(參見上面的Spring文檔)。

此方法允許您避免拆分類,但在許多方面否定了使用事務性註釋的優點。我個人的觀點是,這是一個有點醜陋的東西,但是這個醜陋是自成一體的,如果使用了很多交易,它可能是實用的方法。

切換到使用AspectJ

由於AspectJ中不使用代理服務器,然後自我調用是沒有問題的

這是雖然一個非常乾淨的方法 - 這是在引入另一個框架的代價。我曾在一個大型項目上介紹過AspectJ,因爲這個原因。

不要使用@Transactional在所有

重構代碼使用手動事務劃分 - 可能使用Decorator模式。

一種選擇 - 而是需要適度的重構,引入額外的框架關係,並增加了複雜性 - 因此可能不是一個最佳的選擇

我的建議

通常分手了的代碼是最好的答案,也可以分擔擔憂也是好事。但是,如果我有一個嚴重依賴嵌套事務的框架/應用程序,我會考慮使用AspectJ來允許自我調用。

+0

到目前爲止感謝最好的答案。所以我想我會使用AopContext.currentProxy()只在一些非常特定的情況下,因爲我不是一個沉重的transactionnal應用程序 –

3

我一般都簡單,所以我的代碼分成兩個對象。

另一種方法是給自己劃定新的事務,如果你需要保持在同一個文件的一切,用TransactionTemplate。還有幾行代碼,但不超過定義一個新的bean。有時候這點更加明顯。

4

與往常一樣,在建模和設計複雜用例時 - 關注可理解和可維護的設計和代碼。如果您更喜歡某種特定的模式或設計,但它與底層框架發生衝突,請考慮是否值得采用複雜的解決方法來將您的設計強化爲框架,或者如果您需要在必要時妥協並使您的設計符合框架。除非你絕對需要,否則不要打架。

我的建議 - 如果你能通過這樣一個簡單的妥協來完成你的目標,並分解成幾個額外的服務類別 - 那就做吧。這聽起來比替代品在時間,測試和痛苦方面要便宜得多。這聽起來更容易維護,而且讓下一個接手的人更容易頭痛。

+0

實際上,將代理服務器注入代理類似乎對我來說非常簡單,它確保您的交易適用於內部呼叫,難道您不認爲這是一個簡單的解決方法嗎? –

+0

@SebastienLorber - 我認爲這是一個非常好的折衷方案(我自己做過幾次,爲了解決Spring AOP中的這種限制),只要在javadoc/comments中記錄它,以便下一個人瞭解你正在做,爲什麼。 – pap

+0

這是真的。我認爲這個問題是衆所周知的,但對於新人javadoc是值得歡迎的......我仍然想知道「現在是哪一種春天」的意思。這個問題也許已經解決了? –