组件注入 # 注入的属性_注入域对象而不是基础结构组件
組件注入 # 注入的屬性
依賴注入是Java(以及許多其他編程語言)中廣泛使用的軟件設計模式,用于實現控制反轉 。 它提高了可重用性,可測試性,可維護性,并有助于構建松耦合的組件。 如今,依賴注入是將Java對象連接在一起的事實上的標準。
諸如Spring或Guice之類的各種Java框架可以幫助實現依賴注入。 從Java EE 6開始,還有一個正式的Java EE API用于依賴關系注入: 上下文和依賴關系注入 (CDI)。
我們使用依賴注入來注入服務,存儲庫,與域相關的組件,資源或配置值。 但是,以我的經驗,依賴注入也可以用來注入域對象,這常常被忽略。
一個典型的例子是在Java許多應用程序中獲取當前登錄用戶的方式。 通常,我們最終會向登錄用戶詢問某些組件或服務。
此代碼看起來可能類似于以下代碼片段:
public?class?SomeComponent?{@Injectprivate?AuthService?authService;public?void?workWithUser()?{User?loggedInUser?=?authService.getLoggedInUser();//?do?something?with?loggedInUser} }此處,將AuthService實例注入SomeComponent。 SomeComponent的方法現在使用AuthService對象來獲取已登錄用戶的實例。
但是,除了注入AuthService之外,我們還可以將登錄的用戶直接注入SomeComponent。
可能看起來像這樣:
public?class?SomeComponent?{@Inject@LoggedInUserprivate?User?loggedInUser;public?void?workWithUser()?{//?do?something?with?loggedInUser} }在這里,User對象直接注入SomeComponent中,不需要AuthService實例。 如果存在多個類型為User的(托管)bean,則使用自定義批注@LoggedInUser來避免沖突。
Spring和CDI都可以進行這種類型的注入(并且配置實際上非常相似)。 在下一節中,我們將看到如何使用Spring注入域對象。 在此之后,我將描述對CDI進行相同操作需要進行哪些更改。
使用Spring進行域對象注入
要注入上面示例中所示的域對象,我們只需要做兩個小步驟。
首先,我們必須創建@LoggedInUser批注:
import?java.lang.annotation.*; import?org.springframework.beans.factory.annotation.Qualifier;@Target({ElementType.FIELD,?ElementType.PARAMETER,?ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public?@interface?LoggedInUser?{}請注意@Qualifier批注,它將@LoggedInUser轉換為自定義限定符。 如果有多個相同類型的bean可用,Spring會使用限定符來避免沖突。
接下來,我們必須在我們的Spring配置中添加一個bean定義。 我們在這里使用Spring的Java配置,使用xml配置也可以完成。
@Configuration public?class?Application?{@Bean@LoggedInUser@Scope(value?=?WebApplicationContext.SCOPE_SESSION,?proxyMode?=?ScopedProxyMode.TARGET_CLASS)public?User?getLoggedInUser()?{//?retrieve?and?return?user?object?from?server/database/session} }在getLoggedInUser()內部,我們必須檢索并返回當前登錄用戶的實例(例如,通過從第一個片段中詢問AuthService)。 使用@Scope,我們可以控制返回對象的范圍。 最佳范圍取決于域對象,并且在不同的域對象之間可能有所不同。 對于代表已登錄用戶的User對象, 請求或會話范圍將是有效的選擇。 通過用@LoggedInUser注釋getLoggedInUser(),我們告訴Spring應該在每次注入用戶類型為@LoggedInUser的bean時使用此bean定義。
現在,我們可以將登錄用戶注入到其他組件中:
@Component public?class?SomeComponent?{@Autowired@LoggedInUserprivate?User?loggedInUser;... }在這個簡單的示例中,實際上不需要限定符注釋。 只要只有一個類型為User的bean定義可用,Spring可以按類型注入已登錄的用戶。 但是,在注入域對象時,很容易發生您具有相同類型的多個bean定義。 因此,使用附加的限定符注釋是一個好主意。 限定符還可以使用其描述性名稱充當文檔(如果命名正確)。
簡化Spring bean定義
注入許多域對象時,最終有可能在bean配置中一遍又一遍地重復作用域和代理配置。 在這種情況下,Spring注釋可以在自定義注釋上使用非常方便。 因此,我們可以簡單地創建自己的@SessionScopedBean批注,以代替@Bean和@Scope:
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Bean @Scope(value?=?WebApplicationContext.SCOPE_SESSION,?proxyMode?=?ScopedProxyMode.TARGET_CLASS) public?@interface?SessionScopedBean?{}現在我們可以簡化bean的定義:
@Configuration public?class?Application?{@LoggedInUser@SessionScopedBeanpublic?User?getLoggedInUser()?{...} }Java EE和CDI
CDI的配置幾乎相同。 唯一的區別是我們必須用javax.inject和CDI注釋替換Spring注釋。
因此,@LoggedInUser應該使用javax.inject.Qualifier而不是org.springframework.beans.factory.annotation.Qualifier進行注釋(請參閱: 使用Qualifiers )。
Spring bean定義可以用CDI Producer方法代替。 可以使用適當的CDI范圍注釋代替@Scope。
在注入點,可以將Spring的@Autowired替換為@Inject。
請注意,Spring還支持javax.inject注釋。 如果將javax.inject依賴項添加到Spring項目中,則還可以使用@Inject和@ javax.inject.Qualifier。 這樣做實際上是一個好主意,因為它可以減少Java代碼中的Spring依賴關系。
結論
我們可以使用自定義注釋和作用域bean將域對象注入其他組件。 注入域對象可以使您的代碼更易于閱讀,并且可以導致更清晰的依賴關系。 如果僅注入AuthService來獲取登錄用戶,則實際上取決于登錄用戶而不是AuthService。
不利的一面是,它使您的代碼更牢固地依賴于依賴注入框架,該框架必須為您管理bean范圍。 如果要保持在Dependency Injection容器之外使用類的能力,則可能會遇到問題。
哪種類型的域對象適合注入在很大程度上取決于您正在處理的應用程序。 好的候選對象是您經常使用的領域對象,并且不依賴于任何方法或請求參數。 當前登錄的用戶是可能通常適合注入的對象。
- 您可以在GitHub上找到所示示例的源代碼。
翻譯自: https://www.javacodegeeks.com/2014/10/injecting-domain-objects-instead-of-infrastructure-components.html
組件注入 # 注入的屬性
總結
以上是生活随笔為你收集整理的组件注入 # 注入的属性_注入域对象而不是基础结构组件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: openshift命令_使用命令行工具创
- 下一篇: apache karaf_未来是Apac