@Autowired @Resource @Inject的區別

我知道在Spring中,能夠用@autowired @resource @Inject三種方式進行依賴注入,三種方式的區別在什麼地方呢?java

定義測試用例

若是沒有興趣能夠直接跳到下面的結論spring

若是不知道如何測試Spring項目的能夠點擊這裏。ide

首先咱們定義一個Person接口:測試

package site.abely.service;

public interface Person {
    void sayHello();
}

而後定義兩個實現類Chinese,Americanui

package site.abely.service;

import org.springframework.stereotype.Component;

@Component
public class Chinese implements Person {
    @Override
    public void sayHello() {
        System.out.println("你好");
    }
}
package site.abely.service;

import org.springframework.stereotype.Component;

@Component
public class American implements Person {
    @Override
    public void sayHello() {
        System.out.println("Hello");
    }
}

結論

@Autowired

先按類型注入,而後按照名字注入,都沒法找到惟一的一個實現類出錯。.net

咱們將American類中@Component註釋,這樣在Spring環境中只有Chinese一個實現類,測試代碼以下:指針

@Autowired
Person person;
@Test
public void testSay(){
    person.sayHello();
}

輸出你好code

由於只有Chinese實現了Person,因此會正確運行(經過類型查找)。對象

咱們取消American類中@Component的註釋,運行程序會出現異常:接口

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'site.abely.service.Person' available: expected single matching bean but found 2: american,chinese

由於有American和Chinese兩個實現類,Spring不知道該用哪個注入。

修改測試代碼:

@Resource
Person chinese;
@Test
public void testSay(){
    chinese.sayHello();
}

結果會輸出你好。此時變量名chinese等於Chinese默認的Qualifier名字。

若是隻有一個實現類Chinese(刪除American類),並且Chinese不實現Person接口,此時怎麼注入Person chinese都會出錯(請求的是Person對象,注入的卻不是)。

@Autowired(required=false)中若是設置required爲false(默認爲true),則注入失敗時不會拋出異常,但person.sayHello();調用時會出現空指針異常。

@Inject

在Spring的環境下,@Inject和@Autowired是相同的,都是使用AutowiredAnnotationBeanPostProcessor來處理依賴注入,@Inject是jsr-330定義的規範,仍是比較推薦使用這種方式進行依賴注入,若是使用這種方式,切換到Guice也是能夠的。

若是硬要說兩個的區別,首先@Inject是Java EE包裏的,在SE環境須要單獨引入。另外一個區別在於@Autowired能夠設置required=false而@Inject並無這個設置選項。

@Resource

先按名字注入,在按類型注入,都沒法找到惟一的一個出現異常

這是jsr-250定義的規範,相對於jsr-330算是比較老的了。這裏不推薦使用這種注入方式,下面討論一下其注入的問題。

首先咱們註釋American裏的@Component,這樣在Spring託管的Bean裏只有Chinese實現了Person接口,測試用例以下:

@Resource
Person person;
@Test
public void testSay(){
    person.sayHello();
}

輸出結果:你好。 此時@Resource先按名字person,並未找到person的bean,而後按照類型來找,只有Chinese,注入成功。

取消American中的@Component註釋,出現以下異常:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'site.abely.service.Person' available: expected single matching bean but found 2: american,chinese

此時不管經過名字沒法肯定,而後經過類型仍是沒法肯定,拋出異常。

修改測試代碼

@Resource
Person chinese;
@Test
public void testSay(){
    chinese.sayHello();
}

輸出結果你好,此時按名字找到了chinese。

特殊狀況

咱們上面也說了,咱們推薦是用@Inject,不會與Spring產生耦合,固然若是有必要也可使用@Autowired,爲何不推薦使用@Resouce呢?

如今咱們讓Chinese不實現Person接口,但仍然被Spring管理,測試代碼以下:

@Resource
Person chinese;
@Test
public void testSay(){
    chinese.sayHello();
}

結果以下:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'site.abely.service.TestTest': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'chinese' is expected to be of type 'site.abely.service.Person' but was actually of type 'site.abely.service.Chinese'

結果的問題在於,American是Person的惟一實現類並且被Spring託管,此時卻不會被注入。

使用@Autowired輸出Hello

對比你能夠發現@Resource的問題所在,也許你認爲@Resouce的結果是合理的,可是你要考慮到@Qualifier或@Named的做用,咱們能夠用以下代碼取得和@Resouce相似的效果:

@Autowired
@Qualifier("chinese")
Person chinese;

@Test
public void testSay() {
    chinese.sayHello();
}

出現異常:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'site.abely.service.Person' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=chinese)}

這樣也會去找一個bean id爲chinese的bean,在這種狀況下(只有一個實現類),@Resouce要想得到正確的注入只有一個方式,正確的命名Person americanPerson person(person能成功的緣由在於Spring中沒有bean的id爲person的託管類),若是命名不正確,即便使用@Qualifier("american")也不會正確注入(@Resouce不會鳥它的),這會給開發者帶來額外的負擔,即便只有一個實現類,@Resouce也有可能沒法注入。這也是開發中常見的事情,若是你的命名和Sping中某個bean的id相同,@Resouce會出現一些意想不到的問題。

相關文章
相關標籤/搜索