lucky小默
spring中,@Resource和@Autowired都是做bean的注入時使用。使用過程中,有時候@Resource 和 @Autowired可以替換使用;有時,則不可以。
下面,根據自己的學習,整理下這兩個註解使用中的共同點和不同點,及用法上的不同。
共同點
@Resource和@Autowired都可以作為注入屬性的修飾,在接口僅有單一實現類時,兩個註解的修飾效果相同,可以互相替換,不影響使用。
不同點
@Resource是Java自己的註解,@Resource有兩個屬性是比較重要的,分是name和type;Spring將@Resource註解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。所以如果使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。如果既不指定name也不指定type屬性,這時將通過反射機制使用byName自動注入策略。
@Autowired是spring的註解,是spring2.5版本引入的,Autowired只根據type進行注入,不會去匹配name。如果涉及到type無法辨別注入對象時,那需要依賴@Qualifier或@Primary註解一起來修飾。
我們創建一個簡單的springboot項目demo,
定義一個接口Human.java,裡面一個方法 runMarathon,
一個實現類Man.java
一個Controller類HumanController.java,裡面注入Human接口的實現
附各Java類源碼
package com.example.annotation.service;
/**
* service接口定義
* @author Administrator
*/
public interface Human {
/**
* 跑馬拉松
* @return
*/
String runMarathon();
}
package com.example.annotation.service.impl;
import com.example.annotation.service.Human;
import org.springframework.stereotype.Service;
/**
* service接口第一實現類
* @author Administrator
*/
@Service
public class Man implements Human {
public String runMarathon() {
return "A man run marathon";
}
}
package com.example.annotation.controller;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.annotation.service.Human;
/**
* controller層實現類
* @author Administrator
*/
@RestController
@RequestMapping("/an")
public class HumanController {
@Resource
private Human human;
@RequestMapping("/run")
public String runMarathon() {
return human.runMarathon();
}
}
至此,代碼整理完成,啟動springboot,瀏覽器地址欄輸入http://localhost:8080/an/run
改動一:
將HumanController.java 類中的註解替換為@Autowired,再次啟動,可以正常訪問,與上圖相同,這裡不再貼訪問結果圖。
改動二:
再增加一個實現類Woman.java
package com.example.annotation.service.impl;
import com.example.annotation.service.Human;
import org.springframework.stereotype.Service;
/**
* service接口第二實現類
* @author Administrator
*/
@Service
public class Woman implements Human {
public String runMarathon() {
return "An woman run marathon";
}
}
HumanController.java 註解使用@Resource
@Resource
private Human human;
啟動springboot,控制檯會報錯,報錯信息太多,截取關鍵信息
2018-09-10 16:07:10.362 WARN 5592 --- [ restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'humanController': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.annotation.service.Human' available: expected single matching bean but found 2: man,woman
找關鍵信息 expected single matching bean but found 2: man,woman,被期望的單一結果被匹配到兩個結果man和woman。
這裡,我們需要藉助@Resource註解的name屬性或@Qualifier來確定一個合格的實現類
代碼修改為
@Resource(name="woman")
private Human human;
或
@Resource
@Qualifier("woman")
private Human human;
上面,我們指定了Human接口的實現類是Woman.java,啟動springboot,訪問 http://localhost:8080/an/run
改動三:
在改動二的基礎上,將註解替換為@Autowired,啟動報錯
Description:
Field human in com.example.annotation.controller.HumanController required a single bean, but 2 were found:
- man: defined in file [D:\\DEV_ENV\\springbootws\\annotation\\target\\classes\\com\\example\\annotation\\service\\impl\\Man.class]
- woman: defined in file [D:\\DEV_ENV\\springbootws\\annotation\\target\\classes\\com\\example\\annotation\\service\\impl\\Woman.class]
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
報錯信息很明顯,HumanController需要一個bean實現,但是找到了兩個 man 和woman
解決方案:使用@Primary註解,在有多個實現bean時告訴spring首先@Primary修飾的那個;或者使用@Qualifier來標註需要注入的類。
@Qualifier修改方式與改動二的相同,依然是修改HumanController.java 中間注入的Human上面,這裡不再複述
@Primary是修飾實現類的,告訴spring,如果有多個實現類時,優先注入被@Primary註解修飾的那個。這裡,我們希望注入Man.java ,那麼修改Man.java為
package com.example.annotation.service.impl;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import com.example.annotation.service.Human;
/**
* service接口第一實現類
* @author Administrator
*/
@Service
@Primary
public class Man implements Human {
public String runMarathon() {
return "A man run marathon";
}
}
啟動springboot後,可以看到注入的已經是Man.java 了。
Java架構達人
一、共同的用途
做bean的注入時使用
裝配bean. 寫在字段上,或寫在setter方法
二、不同點
@Autowired
屬於Spring的註解 org.springframework.beans.factory.annotation.Autowired
@Autowired 默認按類型裝配,依賴對象必須存在,如果要允許null值,可以設置它的required屬性為false @Autowired(required=false),也可以使用名稱裝配,配合@Qualifier註解
@Resource
不屬於Spring的註解,JDK1.6支持的註解 javax.annotation.Resource
@Resource 默認按名稱進行裝配,通過name屬性進行指定
三、總結
@Autowired自動註解,舉個例子吧,一個類,倆個實現類,Autowired就不知道注入哪一個實現類。
Resource有name屬性,可以區分。