Spring中@Resource和@Autowire的區別

1、實踐出真知

@Resource 是 JSR-250 規範的一部分

說到 @Resource 大家肯定會想到 @Autowired, 至於兩者的區別, 大部門分童鞋都知道。


@Resource 的作用和 @Autowired 一樣,只不過 @Autowired 是按 byType 自動注入,而 @Resource 默認按 byName 自動注入,而且還提供了 name 和 type 兩個屬性,其含義也容易理解,分別按 byName 和 byType 注入。

如果兩個屬性都沒有提供的話,則根據屬性名稱注入,我理解的是 byName,還有地方說是通過反射機制使用 byName自動注入。

俗話說的好 no tu no bb,接下來多圖慎入。下圖爲測試項目的結構。

 

(1)@Autowired,匹配多個實現類,但默認屬性名匹配不上,報錯

我們先來看看 @Autowired 的測試情況。

我通過在 SpringTest 類的 Main 方法中,初始化和啓動 Spring 容器。配置中配置了兩個 MyTestService 接口的實現類 MyTestServiceImpl2 和 MyTestServiceImpl3,打印了簡單的一句話。結果肯定顯而易見,報錯了。

我在 註解@Service 中配置了兩個實現類,默認按 byType 注入,發現多個,根據 byName注入,無法找到 name 爲 myTestService 的 bean,所以報錯了,接下來修改屬性名,再看。

 

(2)@Autowired,匹配多個實現類,默認屬性名匹配上其中一個,正常

這次同樣的步驟,默認按 byType 注入,發現多個,根據 byName 注入,找到 name 爲 myTestServiceImpl2 的 Bean。成功執行。

 

(3)@Resource 沒指定name屬性,且默認屬性名匹配不上,但只匹配上一個實現類,正常

來看看 @Resource 的情況,請看下圖配置,我註釋掉了 MyTestServiceImpl2 實現類的聲明。

注意 HomeController 中聲明的屬性 myTestService,在配置中沒有這個屬性對應的 Bean,@Resource 沒有配置 name 和 type 的情況下,結果是什麼呢?現在大家猜一下執行成功還是失敗。

是的,沒有報錯,你猜對了嗎?那好現在我們把 HomeController 中的屬性名稱再改一下。

 

(4)@Resource 沒指定name屬性,但默認屬性名匹配,正常

我把屬性改爲存在的 Bean,myTestServiceImpl3,然後我們再來看看結果,毫無疑問結果肯定是沒有報錯。

那好,按照以上測試結果來看,當 @Resource 沒有提供 name 和 type 屬性的時候,如果 byName 沒有找到對應的 Bean 時,則會根據依賴屬性的類型去 Spring 容器中查找是否有提供了其他類型相同的 Bean,如果有則自動注入,如果沒有則報錯。當然如果根據 byName 找到了則直接注入。接下來,我們再來看看,name 和 type 的情況。

 

(5)@Resource 指定name屬性,但屬性名不匹配,報錯

我在 HomeController 中添加了 @Resource 的 name 屬性 爲 myTestServiceImpl2,那麼現在如果執行,結果是否會報錯?

是的報錯了,因爲註釋了 myTestServiceImpl2 的聲明,所以在使用 name 屬性查找時,無法找到對應的 Bean,所以直接報錯,沒有再次去通過類型到 Spring 容器中查找。接下來我們再看看使用配置的 Bean的情況。

 

(6)@Resource 指定name屬性,屬性名匹配,正常

我使用了 userDaoImpl1 這個 Bean,那結果顯而易見,肯定沒有問題。

type 屬性我就不用演示了吧,和 name 屬性是一樣,如果同時提供了 name 和 type 的話,那就必須兩個都要匹配才能注入依賴,否則就會注入失敗。總算把 @Resource 註解搞明白了,之前一直以爲 @Resource 註解就是默認 byName 裝配,不知道里面還有這麼多彎彎繞呢。

 

2、@Autowired

@Autowired默認byType自動注入,如果實例結果不唯一,那麼將會拋出異常

@Autowired可與@Qualifier("beanName")搭配使用,注入指定bean。

@Autowired
@Qualifier("baseDao")
private BaseDao baseDao;

如,同一個接口,兩個實現類,就可以使用該方式指定注入。

@Autowired(required=false)表示如果spring上下文中沒有找到該類型的bean ,將會使用

new SoftPMServiceImpl();

private ISoftPMService softPMService = new SoftPMServiceImpl();

 

3、@Resource

@Resource默認按byName自動注入
但是@Resource有兩個屬性是比較重要的,分別是name和type;
如果使用name屬性,則使用byName的自動注入策略; .
而使用type屬性時則使用byType自動注入策略;

@Resource裝配順序
  1. 如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則拋出異常
  2. 如果指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常
  3. 如果指定了type,則從上下文中找到類型匹配的唯一bean進行裝配,找不到或者找到多個,都會拋出異常
  4. 如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;如果沒有匹配,則回退爲一個原始類型進行匹配,如果匹配則自動裝配;

使用方式如下:

//@Resource(name="dataSource");

@Resource(type="DataSource.class");

@Resource
private DataSource dataSource;
//inject the bean named 'dataSource';

 

4、簡要對比表格

註解對比 @Resource @Autowire
註解來源 JDK Spring
裝配方式 優先按名稱 優先按類型
屬性 name、type required


參考:

https://zhuanlan.zhihu.com/p/114376607

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章