簡體   English   中英

Java依賴注入:XML或注釋

[英]Java Dependency injection: XML or annotations

注釋變得流行。 Spring-3支持它們。 CDI嚴重依賴它們(我不能在沒有注釋的情況下使用CDI,對吧?)

我的問題是為什么

我聽到幾個問題:

  1. “它有助於擺脫XML”。 但是xml有什么不好的? 依賴性本質上是聲明性的,XML對於聲明非常有用(對於命令式編程來說非常糟糕)。 有了很好的IDE(就像想法一樣),編輯和驗證xml非常容易,不是嗎?

  2. “在許多情況下,每個接口只有一個實現”。 那不是真的! 我系統中的幾乎所有接口都具有用於測試的模擬實現。

還有其他問題嗎?

現在我的XML優勢:

  1. 你可以在任何地方注入任何東西(不僅是帶有注釋的代碼)

  2. 如果我有一個接口的多個實現,我該怎么辦? 使用限定符? 但它迫使我的班級知道它需要什么樣的注射。 它不適合設計。

基於XML的DI使我的代碼清晰:每個類都不知道注入,所以我可以配置它並以任何方式對它進行單元測試。

你怎么看?

我只能用Guice的經驗說話,但這是我的看法。 缺點是基於注釋的配置大大減少了將應用程序連接在一起所需的寫入量,並且可以更容易地根據什么來改變...通常甚至不必自己觸摸配置文件。 它通過使最常見的情況絕對無足輕重而犧牲了使某些相對罕見的情況稍微難以處理。

我認為讓課程“不知道注射”太過教條是一個問題。 在類的代碼中不應該引用注入容器。 我絕對同意這一點。 但是,我們必須明確一點:注釋不是代碼 它們本身並沒有改變類的行為......你仍然可以創建一個帶有注釋的類的實例,好像它們根本就不存在一樣。 所以你可以完全停止使用DI容器並在那里留下注釋,這樣就不會有任何問題。

當您選擇不提供有關類中注入的元數據提示(即注釋)時,您將丟棄有關該類所需依賴項的寶貴信息源。 您不得不在其他地方重復這些信息(例如XML),或依賴不可靠的魔法,如自動裝配,這可能會導致意外問題。

要解決您的一些具體問題:

它有助於擺脫XML

XML配置很多都很糟糕。

  • 這非常冗長。
  • 沒有特殊工具,它不是類型安全的。
  • 它要求使用字符串標識符。 同樣,沒有特殊工具支持也不安全。
  • 不利用語言的功能,需要各種丑陋的構造來完成可以通過代碼中的簡單方法完成的任務。

也就是說,我知道很多人已經使用XML足夠長的時間,以至於他們確信它很好,我真的不希望改變他們的想法。

在許多情況下,每個接口只有一個實現

對於應用程序的單個配置 (例如,生產),每個接口通常只有一個實現。 關鍵是在啟動應用程序時,通常只需要將接口綁定到單個實現。 然后它可以用在許多其他組件中。 使用XML配置,您必須告訴使用該接口的每個組件使用該接口的特定綁定(如果您願意,還可以使用“bean”)。 使用基於注釋的配置,您只需聲明綁定一次 ,其他所有內容都會自動處理。 這非常重要,可以顯着減少您必須編寫的配置量。 這也意味着當您向組件添加新依賴項時,通常不必更改任何有關配置的內容!

你有一些接口的模擬實現是無關緊要的。 在單元測試中,您通常只需創建模擬並將其傳遞給自己...它與配置無關。 如果你使用模擬設置一個完整的系統進行集成測試與某些接口......這不會改變任何東西。 對於系統的集成測試運行,您仍然只使用1個實現,而您只需配置一次。

XML:你可以隨處注入任何東西

您可以在Guice中輕松完成此操作,我想您也可以在CDI中完成此操作。 因此,使用基於注釋的配置系統絕對不會阻止您這樣做。 也就是說,我冒昧地說,大多數應用程序中的大多數注入類都是可以為自己添加@Inject類,如果它還沒有。 用於注釋的輕量級標准Java庫(JSR-330)的存在使得更多的庫和框架在將來更容易為組件提供帶有@Inject注釋的構造函數。

一個接口的多個實現

限定詞就是一個解決方案,在大多數情況下應該沒問題。 然而,在某些情況下,你想在那里使用在特定的注射類是行不通的參數的預選賽做一些事情......往往是因為你想有一個類的多個實例,每個實例使用不同的接口實現或實例。 Guice用名為PrivateModule的東西來解決這個問題。 我不知道CDI在這方面提供了什么。 但同樣,這是一個少數情況下的例子,只要你可以處理它就不值得讓你的其余配置受到影響。

我有以下原則:配置相關的bean是用XML定義的。 其他一切 - 帶注釋。

為什么? 因為您不想在類中更改配置。 另一方面,在要啟用的類中編寫@Service@Inject要簡單得多。

這不會以任何方式干擾測試 - 注釋只是容器解析的元數據。 如果您願意,可以設置不同的依賴項。

至於CDI - 它有XML配置的擴展,但你是對的,它主要使用注釋。 這是我不喜歡的東西。

正如你所指出的,我喜歡保持我的代碼清晰。 在國際奧委會的原則中,至少對我來說,XML更好。

配置依賴注入的基本原則是應用程序對象不應負責查找它們所依賴的資源或協作者。 相反,IoC容器應配置對象,將應用程序代碼中的資源查找外部化到容器中。 (沒有EJB的J2EE開發 - Rod Johnson - 第131頁)

再次,這只是我的觀點,那里沒有原教旨主義:)

編輯:一些有用的討論:

在我看來,這更多的是品味問題。

1)在我們的項目中(使用Spring 3),我們希望XML配置文件就是:配置。 如果不需要配置(從最終用戶的角度來看)或某些其他問題不強制它在xml中完成,請不要將bean-definitions / wirings放入XML配置中,使用@Autowired等等。

2)使用Spring,您可以使用@Qualifier來匹配接口的某個實現(如果存在多個)。 是的,這意味着你必須命名實際的實現,但我不介意。

在我們的例子中,使用XML來處理所有DI會使XML配置文件膨脹很多,盡管它可以在一個單獨的xml文件(或文件)中完成,所以它不是那個有效點;)。 正如我所說,這是一個品味問題我只是認為通過注釋處理注入更容易,更干凈(你可以通過查看類而不是通過XML文件來查看什么服務/存儲庫/任何東西使用尋找豆子宣言)。

編輯:這是關於@Autowired與XML的觀點,我完全贊同: Spring @Autowired用法

“但是xml的壞處是什么?” 這是另一個要管理的文件,還有另一個必須去尋找bug的地方。 如果您的注釋正好在您的代碼旁邊,那么管理和調試就會容易得多。

像所有事情一樣,應該適度使用依賴注入。 此外,注入的所有陷阱應與應用程序代碼分開,並降級為與main相關的代碼。

通常,應用程序應具有將抽象應用程序代碼與具體實現細節分開的邊界。 跨越該邊界的所有源代碼依賴項應指向應用程序。 我稱那個邊界的具體方面是主分區,因為那就是'main'(或者它的等價物)應該存在的地方。

主分區由工廠實現,策略實現等組成。在邊界的這一邊,依賴注入框架應該做它的工作。 然后,這些注入的依賴項可以通過常規方式跨越邊界傳遞到應用程序中。 (例如作為參數)。

注入的依賴項的數量應該相對較小。 十幾個或更少。 在這種情況下,XML或注釋之間的決定沒有實際意義。

另外不要忘記Spring JavaConfig

在我看來,編寫應用程序的開發人員與配置應用程序的開發人員(不同的部門,不同的技術/語言)不同,最后一組甚至無法訪問源代碼(許多企業設置就是這種情況)。 這使得Guice無法使用,因為我必須公開源代碼而不是使用由實現app的開發人員配置的xml。

總的來說,我認為重要的是要認識到提供組件和組裝/配置應用程序是兩個不同的練習,並在需要時提供這種關注點分離。

XML具有聲明式樣式的唯一優點,聲明式樣式與應用程序代碼本身明確分開。 這與DI問題無關。 缺點是冗長,重新分解魯棒性差和一般的運行時故障行為。 與IDE支持例如Java相比,只有一般的(XML)工具支持幾乎沒有什么好處。 除此之外,XML還帶來了性能開銷,因此它通常比代碼解決方案慢。

在重新分解應用程序代碼時, Annoations通常被認為更直觀,更健壯。 他們也受益於像guice提供的更好的IDE指導。 但他們將應用程序代碼與DI問題混在一起 應用程序依賴於框架。 清除分離幾乎是不可能的。 當根據其他情況(例如機器人腿問題)在同一位置(構造函數,字段)描述不同的注入行為時,注釋也受到限制。 此外,它們不允許像處理自己的源一樣處理外部類(庫代碼)。 因此,它們被認為比XML運行得更快。

這兩種技術都有嚴重的缺點。 因此我建議使用Silk DI 它是在代碼中聲明性定義的(很棒的IDE支持),但是100%與應用程序代碼分開(沒有框架依賴性)。 它允許對所有代碼進行相同處理,無論它來自您的源代碼還是外部庫。 通常的綁定很容易解決機器人腿問題等問題 此外,它有很好的支持,以適應您的需求。

我剛剛在這里添加了一些東西。

  • 對我來說,DI配置是代碼。 我想這樣對待它,但XML的本質在沒有額外工具的情況下阻止了這種情況。

  • Spring JavaConfig是這方面的重大進步,但它仍然存在復雜性。 組件掃描,接口實現的自動魔術選擇以及圍繞@Configuration注釋類的CGLIB攔截的語義使得它比它需要的更復雜。 但它仍然是XML的一大進步。

  • 將IoC元數據與應用程序對象分離的好處被誇大了,特別是對於Spring。 也許如果你只限於Spring IoC容器,那就是這樣。 但Spring提供了基於IoC容器(安全性,Web MVC等)構建的廣泛應用程序堆棧。 一旦你利用其中的任何一個,你就會被綁在容器上。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM