深入分析@Resource和@Autowired注解區(qū)別
引言
@Resource和@Autowired都是Spring Framework中用于依賴(lài)注入的注解,但它們有幾點(diǎn)不同:
來(lái)源不同:@Resource注解來(lái)自于J2EE規(guī)范中;而@Autowired注解是Spring框架提供的。
搜索策略不同:@Resource注解默認(rèn)按照名稱(chēng)進(jìn)行匹配查找,如果找不到,則按照類(lèi)型進(jìn)行匹配。而@Autowired注解默認(rèn)是按照類(lèi)型進(jìn)行匹配,如果出現(xiàn)多個(gè)類(lèi)型一致的實(shí)例對(duì)象,則需要指定名稱(chēng)。
屬性不同:@Resource注解沒(méi)有屬性名稱(chēng),只有一個(gè)name屬性,表示要注入的Bean名稱(chēng)。而@Autowired注解有兩個(gè)重要屬性:required和name,其中required屬性表示是否必須注入該屬性,默認(rèn)為true;name屬性表示要注入的Bean名稱(chēng)。
1、用法層面分析
首先,我們創(chuàng)建一個(gè)接口UserService和兩個(gè)實(shí)現(xiàn)類(lèi)UserServiceImpl1和UserServiceImpl2。
public interface UserService {
void save();
}
@Service
public class UserServiceImpl1 implements UserService {
@Override
public void save() {
System.out.println("UserServiceImpl1 save");
}
}
@Service
public class UserServiceImpl2 implements UserService {
@Override
public void save() {
System.out.println("UserServiceImpl2 save");
}
}
然后,我們可以在需要使用UserService的地方進(jìn)行依賴(lài)注入。
使用@Resource注解:
@Component
public class UserController {
@Resource
private UserService userService;
// ...
}
使用@Autowired注解:
@Component
public class UserController {
@Autowired(required = false)
@Qualifier("userServiceImpl1")
private UserService userService;
// ...
}
上面的代碼中,@Resource注解直接將UserService對(duì)象注入到userService屬性中,而@Autowired注解需要結(jié)合@Qualifier注解來(lái)指定具體的Bean名稱(chēng),并且通過(guò)required屬性設(shè)置是否必須注入該屬性。注意,@Autowired注解也可以省略@Qualifier注解,此時(shí)會(huì)按照類(lèi)型進(jìn)行匹配查找對(duì)應(yīng)的Bean。
2、概念層面分析
再來(lái)分析一下其中的道道~~
Spring Framework中的依賴(lài)注入實(shí)現(xiàn)原理是基于Java反射機(jī)制和JavaBean規(guī)范的。
- 通過(guò)反射機(jī)制實(shí)例化對(duì)象
Spring框架通過(guò)反射機(jī)制實(shí)例化需要注入的Bean對(duì)象,并將其存儲(chǔ)到一個(gè)Map中,其中Key為Bean名稱(chēng),Value為Bean實(shí)例對(duì)象。
- 通過(guò)JavaBean規(guī)范完成Bean屬性注入
接下來(lái),Spring會(huì)根據(jù)JavaBean規(guī)范(即屬性名以及該屬性的setter方法)查找需要注入的屬性,并通過(guò)反射機(jī)制調(diào)用對(duì)應(yīng)的setter方法進(jìn)行屬性注入。
- 依賴(lài)注入的搜索策略
在依賴(lài)注入的過(guò)程中,Spring框架通常采用兩種搜索策略:
- 按照類(lèi)型搜索:當(dāng)需要注入的屬性的類(lèi)型與容器中的多個(gè)Bean的類(lèi)型一致時(shí),會(huì)根據(jù)不同的注解選擇不同的搜索策略。比如使用@Autowired注解時(shí),默認(rèn)按照類(lèi)型匹配查找對(duì)應(yīng)的Bean。
- 按照名稱(chēng)搜索:當(dāng)需要注入的屬性的類(lèi)型不唯一,或者需要注入的Bean名稱(chēng)與屬性名稱(chēng)不一致時(shí),可以使用@Qualifier注解指定要注入的Bean名稱(chēng)。
- 使用各種注解進(jìn)行依賴(lài)注入
Spring框架提供了多種注解用于依賴(lài)注入,包括:
- @Autowired:按照類(lèi)型進(jìn)行注入;
- @Resource:按照名稱(chēng)進(jìn)行注入;
- @Value:注入簡(jiǎn)單類(lèi)型或字符串類(lèi)型的屬性;
- @Inject:JSR-330標(biāo)準(zhǔn)定義的注解,功能與@Autowired類(lèi)似。
Spring Framework的依賴(lài)注入實(shí)現(xiàn)原理是基于Java反射機(jī)制和JavaBean規(guī)范的,并通過(guò)多種注解實(shí)現(xiàn)不同的依賴(lài)注入方式。
@Resource和@Autowired都是Spring的依賴(lài)注入注解,但它們有如下區(qū)別:
來(lái)源不同:@Resource是Java EE規(guī)范定義的注解,而@Autowired是Spring提供的注解。
屬性不同:@Resource注解沒(méi)有required屬性,只有name屬性,表示要注入的Bean名稱(chēng);而@Autowired注解有required和name屬性,其中required表示是否必須注入該屬性,默認(rèn)為true;name表示要注入的Bean名稱(chēng)。
查找方式不同:@Resource注解默認(rèn)是根據(jù)byName的方式進(jìn)行查找,如果找不到則按照byType進(jìn)行查找;而@Autowired默認(rèn)是根據(jù)byType方式進(jìn)行查找。
兼容性不同:@Resource注解可以與JSR-330的@Inject注解搭配使用;而@Autowired注解只能與Spring組件一起使用。
應(yīng)用場(chǎng)景不同:@Resource注解主要應(yīng)用于Java EE環(huán)境,而@Autowired注解則是在Spring框架中使用最廣泛的依賴(lài)注入注解之一,可以適用于不同的應(yīng)用場(chǎng)景。
下面分別介紹@Resource和@Autowired注解的優(yōu)缺點(diǎn):
@Resource優(yōu)點(diǎn):
簡(jiǎn)單易用,在類(lèi)中使用非常方便。
可以和@Inject注解一起使用。
支持指定Bean名稱(chēng),可以更精確地進(jìn)行依賴(lài)注入。
@Resource缺點(diǎn):
Spring框架對(duì)@Resource注解的支持不如@Autowired豐富。
僅支持byName和byType兩種注入方式,比@Autowired的支持更為有限。
@Autowired優(yōu)點(diǎn):
支持復(fù)雜的依賴(lài)注入配置,可以通過(guò)多種方式進(jìn)行依賴(lài)注入。
Spring框架對(duì)@Autowired注解的支持非常豐富,是Spring中使用最廣泛的注解之一。
可以指定是否必須注入該屬性,也可以指定Bean名稱(chēng)進(jìn)行注入。
除了在類(lèi)中使用之外,還可以在構(gòu)造方法、Setter方法及任何標(biāo)記了@Bean的方法中使用@Autowired注解。
@Autowired缺點(diǎn):
配置較為繁瑣,需要指定required和name屬性等。
需要遵循Spring的自動(dòng)掃描機(jī)制,只有標(biāo)記了@Component、@Service、@Controller和@Repository等注解的類(lèi)才會(huì)被Spring容器進(jìn)行管理。
對(duì)于依賴(lài)注入的原理,可以簡(jiǎn)單地概括為以下三個(gè)步驟:
在應(yīng)用程序啟動(dòng)時(shí),Spring容器負(fù)責(zé)創(chuàng)建和管理所有的Bean實(shí)例對(duì)象。
在需要使用某個(gè)Bean的時(shí)候,Spring容器會(huì)通過(guò)反射機(jī)制將該Bean注入到需要使用的類(lèi)或?qū)ο笾小?/p>
在Bean注入的過(guò)程中,Spring容器會(huì)根據(jù)不同的注解(如@Resource、@Autowired)采用不同的依賴(lài)注入方式,完成依賴(lài)注入的過(guò)程。
@Resouce和@Autowired都是Spring提供的依賴(lài)注入注解,各有優(yōu)缺點(diǎn)。在實(shí)際開(kāi)發(fā)中,可以根據(jù)具體的應(yīng)用場(chǎng)景選擇合適的注解進(jìn)行使用。
3、源碼層面分析
在Spring Framework源碼層面,@Resource和@Autowired注解的實(shí)現(xiàn)類(lèi)分別為javax.annotation.Resource和org.springframework.beans.factory.annotation.Autowired。下面我們來(lái)看一下它們的具體實(shí)現(xiàn)。
@Resource注解的實(shí)現(xiàn)原理:
- 如果@Resource注解的name屬性不為空,則Spring容器根據(jù)該屬性值查找需要注入的Bean實(shí)例對(duì)象;如果name屬性為空,則默認(rèn)使用字段名作為Bean名稱(chēng)進(jìn)行查找。
- Spring容器會(huì)先根據(jù)byName注入方式進(jìn)行查找,如果沒(méi)有找到對(duì)應(yīng)的Bean實(shí)例,則根據(jù)byType方式進(jìn)行查找。
- 如果找到了對(duì)應(yīng)的Bean實(shí)例,則使用反射機(jī)制將該Bean實(shí)例注入到需要使用該實(shí)例的類(lèi)或?qū)ο笾小?/li>
- 如果沒(méi)有找到對(duì)應(yīng)的Bean實(shí)例,則拋出NoSuchBeanDefinitionException異常。
代碼示例:
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Resource {
String name() default "";
Class<?> type() default java.lang.Object.class;
boolean shareable() default true;
}
@Autowired注解的實(shí)現(xiàn)原理:
- Spring容器會(huì)根據(jù)AutowiredAnnotationBeanPostProcessor類(lèi)和AutowiredAnnotationBeanPostProcessor類(lèi)的派生類(lèi)進(jìn)行處理,將使用@Autowired注解標(biāo)記的所有屬性注入到需要使用的類(lèi)或?qū)ο笾小?/li>
- 對(duì)于AutowiredAnnotationBeanPostProcessor,其實(shí)現(xiàn)了BeanPostProcessor接口,在Bean實(shí)例化、初始化的過(guò)程中會(huì)攔截@Autowired注解。
- 當(dāng)Spring容器遇到@Autowired注解時(shí),會(huì)自動(dòng)調(diào)用AutowiredAnnotationBeanPostProcessor類(lèi)的postProcessPropertyValues方法,該方法會(huì)根據(jù)不同的注解屬性值進(jìn)行不同的依賴(lài)注入處理。
- 在處理@Autowired注解時(shí),Spring容器默認(rèn)使用byType的方式進(jìn)行查找,如果存在多個(gè)匹配類(lèi)型的Bean,則根據(jù)類(lèi)名進(jìn)行匹配;如果仍然無(wú)法確定注入哪個(gè)Bean,則拋出NoSuchBeanDefinitionException異常。
代碼示例:
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
String value() default "";
}
無(wú)論是@Resource注解還是@Autowired注解,在Spring Framework源碼實(shí)現(xiàn)上都是通過(guò)反射機(jī)制和BeanPostProcessor接口完成依賴(lài)注入的。在實(shí)際開(kāi)發(fā)中,我們可以研究對(duì)應(yīng)的源碼實(shí)現(xiàn),深入了解它們的原理,從而更好地使用這些依賴(lài)注入注解。
以上就是深入分析@Resource和@Autowired注解區(qū)別的詳細(xì)內(nèi)容,更多關(guān)于@Resource @Autowired注解區(qū)別的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JDK8時(shí)間相關(guān)類(lèi)超詳細(xì)總結(jié)(含多個(gè)實(shí)例)
jdk1.8的一些新特性簡(jiǎn)化了代碼的寫(xiě)法,減少了部分開(kāi)發(fā)量,下面這篇文章主要給大家介紹了關(guān)于JDK8時(shí)間相關(guān)類(lèi)超詳細(xì)總結(jié),文中包含了多個(gè)實(shí)例代碼,需要的朋友可以參考下2023-01-01
Docker?快速部署Springboot項(xiàng)目超詳細(xì)最新版
這篇文章主要介紹了Docker?快速部署Springboot項(xiàng)目超詳細(xì)最新版的相關(guān)資料,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
Idea的Generate Sources無(wú)法生成QueryDSL問(wèn)題及解決方法
這篇文章主要介紹了解決Idea的Generate Sources無(wú)法生成QueryDSL問(wèn)題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02
Java多線(xiàn)程中synchronized的工作原理
這篇文章主要介紹了Java多線(xiàn)程中synchronized的工作原理,本期講解 synchronized 工作的原理以及常見(jiàn)的鎖優(yōu)化機(jī)制,相信大家在看完這篇博文后對(duì) synchronized 工作流程有一定的理解,需要的朋友可以參考下2023-07-07
JAVA開(kāi)發(fā)環(huán)境Vs?code配置步驟詳解
這篇文章主要為大家介紹了JAVA開(kāi)發(fā)環(huán)境Vs?code配置步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04
Java語(yǔ)言中&&與& ||與|的區(qū)別是什么
這篇文章主要介紹了Java語(yǔ)言中&&與& ||與|的區(qū)別是什么的相關(guān)資料,需要的朋友可以參考下2017-04-04
一文詳解java如何實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用
從?Java?8?開(kāi)始,便引入了一種稱(chēng)為“流式?API”的編程風(fēng)格,當(dāng)然也被稱(chēng)為“鏈?zhǔn)皆O(shè)置”或“鏈?zhǔn)秸{(diào)用”,本文主要來(lái)和大家討論一下如何實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用,感興趣的可以了解下2023-12-12

