spring下應用@Resource, @Autowired 和 @Inject註解進行依賴注入的差別

爲了探尋 ‘@Resource’, ‘@Autowired’, 和‘@Inject’如何解決依賴注入中的問題,我建立了一個「Party」接口,和它的兩個實現類「Person」,「Organization」。這樣我就能夠在注入Bean的時候沒必要使用具體類型(指使用接口類型便可)。這樣作也方便我研究當一個接口有多個實現類與之匹配的時候Spring是如何解決依賴注入的不肯定性的。spring

public interface Party {}
package com.sourceallies.person;
...
@Component
public class Person implements Party {}
package com.sourceallies.organization;
...
@Component
public class Organization implements Party {}
複製代碼

在Spring的配置文件中設置使用 ‘@Component’註解的兩個實現類所在的包須要進行注入檢查bash

<context:component-scan base-package="com.sourceallies.organization"/>
<context:component-scan base-package="com.sourceallies.person"/>
複製代碼
測試1:不明確的bean注入

這個測試驗證注入Party的時候,當它有多個實現類的狀況性能

@Resource
private Party party;

@Autowired
private Party party;

@Inject
private Party party;
複製代碼

以上三種狀況拋出一樣的 ‘NoSuchBeanDefinitionException’異常,單看異常名稱意味着不存在對應的Bean,不過詳細信息中顯示找到了兩個Bean。測試

org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.sourceallies.Party] is defined: expected single matching bean but found 2: [organization, person]ui

測試2:字段名稱注入
@Resource
private Party person;

@Autowired
private Party person;

@Inject
private Party person;
複製代碼

其中@Resource注入能夠設置可選項‘ name’屬性,如下語法和上面的@Resource註解方式是等效的,可是@Autowired和@Inject就沒有相似的等價方式了。this

@Resource(name="person")
private Party party;
複製代碼

以上三種方式最終都被注入‘Person’ Bean。spa

測試3:字段類型注入
@Resource
private Person party;

@Autowired
private Person party;

@Inject
private Person party;
複製代碼

以上狀況都將注入 ‘Person’ Bean。code

測試4:以實現類的默認名進行注入
@Resource
@Qualifier("person")
private Party party;

@Autowired
@Qualifier("person")
private Party party;

@Inject
@Qualifier("person")
private Party party;
複製代碼

以上狀況都將注入 ‘Person’ Bean。component

測試5:指定實現類的類名

在實現類中使用‘Qualifier’註解指定注入時使用的名稱接口

package com.sourceallies.person;
...
@Component
@Qualifier("personBean")
public class Person implements Party {}
複製代碼

注入的時候一樣使用‘Qualifier’註解指定注入哪個名稱的實現類

@Resource
@Qualifier("personBean")
private Party party;
@Autowired
@Qualifier("personBean")
private Party party;
@Inject
@Qualifier("personBean")
private Party party;
複製代碼

以上狀況都將注入 ‘Person’ Bean。

測試6:集合注入
@Resource
private List<Party> parties;
@Autowired
private List<Party> parties
@Inject
private List<Party> parties;
複製代碼

以上狀況都將注入List中兩個Bean。此方式一樣能夠用‘@Qualifier’限定注入Bean,每個知足指定‘qualifier’的bean纔會被注入到List中。

測試7:不良配置

用毫無關聯的‘bad’做爲‘@Qualifier’指定的匹配名

@Resource
@Qualifier("bad")
private Party person;
@Autowired
@Qualifier("bad")
private Party person;
@Inject
@Qualifier("bad")
private Party person;
複製代碼

這種狀況下使用‘@Resource’註解將會忽略‘@Qualifier’配置,故而‘Person' Bean將被注入。 然後二者將會拋出 ‘NoSuchBeanDefinitionException’ 的錯誤信息,由於找不到與’@Qualifier‘配置相匹配的bean。

org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.sourceallies.Party] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=bad)}

總結

‘@Autowired’ 和‘@Inject’的報錯信息徹底相同,他們都是經過‘AutowiredAnnotationBeanPostProcessor’ 類實現的依賴注入,兩者具備可互換性。

‘@Resource’經過 ‘CommonAnnotationBeanPostProcessor’ 類實現依賴注入,即使如此他們在依賴注入時的表現仍是極爲相近的,如下是他們在實現依賴注入時執行順序的歸納:

@Autowired and @Inject

  1. Matches by Type
  2. Restricts by Qualifiers
  3. Matches by Name

@Resource

  1. Matches by Name
  2. Matches by Type
  3. Restricts by Qualifiers (ignored if match is found by name)

‘@Resource’在依據name注入的時候速度性能表現的比 ‘@Autowired’ 和‘@Inject’優越,但這是微不足道的,不足以做爲優先選擇 ‘@Resource’的緣由。我傾向於使用 ‘@Resource’是由於它配置起來更簡潔。

@Resource(name="person")
@Autowired
@Qualifier("person")
@Inject
@Qualifier("person")
複製代碼

你也許會說使用字段 默認 名稱做爲注入時候的bean name,其餘兩種方式就會同樣簡潔:

@Resource
private Party person;
@Autowired
private Party person;
@Inject
private Party person;
複製代碼

確實如此。可是當你須要重構代碼的時候又如何呢?使用’@Resource‘方式只需簡單修改name屬性便可,而無需觸及注入Bean的名稱(注入Bean的時候贊成使用接口名稱)。因此我建議使用註解方式實現注入的時候遵循如下語法風格:

1.在你的組件中明確限定bean名稱而不是使用默認值[@Component("beanName")]。

2.同時使用’@Resource‘和它的’name'屬性 [@Resource(name="beanName")]。

3.避免使用‘@Qualifier’註解,除非你要建立一系列相似beans的集合。例如,你也許須要創建一個set集合來存放一系列「規則」定義。這個時候能夠選擇‘@Qualifier'註解方式。這種方式使得將大量遵循相同規則的類放入集合中變得容易。

4.使用以下配置限定須要盡心組件掃描的包: [context:component-scan base-package="com.sourceallies.person"]。這樣作能夠減少spring掃描不少無效的包的狀況。 遵循以上原則能加強你的,註解風格的,spring配置的可讀性和穩定性。

相關文章
相關標籤/搜索