@Autowired自動(dòng)裝配,@Bean注入@Primary,@Qualifier優(yōu)先級(jí)講解
Autowired自動(dòng)裝配
spring利用依賴注入(DI),完成對(duì)IOC容器中的各個(gè)組件的依賴關(guān)系賦值
對(duì)同一個(gè)Dao類,既有 @Bean 注解聲明,又有Autowired 自動(dòng)裝配,分析一下幾種情況:
第一種情況
1、如果Dao類中聲明了@Repository,且@ComponentScan 添加了dao掃描,則默認(rèn)會(huì)創(chuàng)建一個(gè)testDao在IOC容器中。
2、如果在config中指定了Bean注解,此時(shí):
a、如果Bean注解的方法名也是testDao ,則會(huì)覆蓋默認(rèn)對(duì)象
1.新建maven工程
<groupId>com.MySpring</groupId> <artifactId>demo</artifactId>
新建TestController.java TestService.java TestDao; 分別建在指定的包內(nèi)
pom.xml 文件如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.MySpring</groupId> <artifactId>demo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.6.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
1.TestController 類:
package com.MySpring.demo.controller; import com.MySpring.demo.service.TestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Controller public class TestController { @Autowired private TestService testService; }
2.TestDao 類:
package com.MySpring.demo.dao; import org.springframework.stereotype.Repository; @Repository public class TestDao { public String getMessage( ) { return message; } public void setMessage( String message ) { this.message = message; } private String message ="1"; @Override public String toString( ) { return "TestDao{" + "message='" + message + '\'' + '}'; } }
3.TestService
package com.MySpring.demo.service; import com.MySpring.demo.dao.TestDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class TestService { @Autowired private TestDao testDao; public void print(){ System.out.printf( "[%s] from testService.\n" ,testDao); } }
4.AppConfig
package com.MySpring.demo; import com.MySpring.demo.dao.TestDao; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan({"com.MySpring.demo.controller","com.MySpring.demo.service","com.MySpring.demo.dao",}) public class AppConfig { @Bean public TestDao testDao(){ TestDao dao = new TestDao(); dao.setMessage( "2" ); return dao; } }
5.新建測(cè)試類:
package com.MySpring.demo; import com.MySpring.demo.dao.TestDao; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan({"com.MySpring.demo.controller","com.MySpring.demo.service","com.MySpring.demo.dao",}) public class AppConfig { @Bean public TestDao testDao(){ TestDao dao = new TestDao(); dao.setMessage( "2" ); return dao; } }
輸出結(jié)果:
第二種情況
如果IOC容器中有兩個(gè)Dao實(shí)例,則@Autowired 自動(dòng)裝配會(huì)根據(jù)變量名稱去IOC容器中尋找,對(duì)應(yīng)的實(shí)例裝載,若找不到則報(bào)錯(cuò),默認(rèn)是必須存在,Autowired 源碼如下:
當(dāng)然,也可以設(shè)置required為false
public @interface Autowired { /** * Declares whether the annotated dependency is required. * <p>Defaults to {@code true}. */ boolean required() default true; }
1. 更改AppConfig類中 Bean注解的方法名為testDao2
2. 同時(shí)更改TestService中的 testDao變量名為 testDao2,其他保持不變:
執(zhí)行測(cè)試用例AppTest,得到結(jié)果,我們可以發(fā)現(xiàn)IOC容器中,有兩個(gè)實(shí)例名稱,Service中Autowired 自動(dòng)裝配的對(duì)象變成了2, 而通過(guò)getBean(“testDao") 得到的結(jié)果是Dao原始的結(jié)果1:
第三種情況
在第二中情況下,如果在@Autowired 注解的變量中聲明@Qualifier(“testDao”),則會(huì)優(yōu)先根據(jù)Qualifier指定的名稱去裝載Bean對(duì)象, 修改TestService代碼如下:
運(yùn)行AppTest測(cè)試用例,結(jié)果如下:
第四種情況
@Qualifier與@Primary注解同時(shí)存在 在第三種情況基礎(chǔ)上,@Bean注解中追加 @Primary注解
更改 AppTest 中獲取 TestDao的方式為 app.getBean(TestDao.class) 如下:
運(yùn)行AppTest 測(cè)試用例,結(jié)果如下:
證明:
@Qualifier是根據(jù)bean id指定獲取testDao, 不受@Primary影響. 但是在沒(méi)有Qualifier 的地方,通過(guò)@Primary標(biāo)記的Bean優(yōu)先被使用。
通過(guò)TestDao{message=‘2'} 可以證明,如果不標(biāo)記Primary Bean,則此處會(huì)報(bào)錯(cuò),因?yàn)橛袃蓚€(gè)相同實(shí)例,Spring不知道該選擇哪個(gè)。
總結(jié)
1、如果Dao類中聲明了@Repository,且@ComponentScan 添加了dao掃描,則默認(rèn)會(huì)創(chuàng)建一個(gè)testDao在IOC容器中。
2、如果在config中指定了Bean注解,此時(shí):
a、如果Bean注解的方法名也是testDao ,則會(huì)覆蓋默認(rèn)對(duì)象
b、如果Bean注解的方法名或者聲明的別名不是testDao ,則會(huì)新創(chuàng)建一個(gè)對(duì)象在IOC容器中。
@Autowired 取值
如果聲明的變量是testDao ,則默認(rèn)會(huì)去IOC容器中獲取testDao對(duì)象。
如果聲明的變量是Bean注解指定的別名或者方法名,則會(huì)去容器中獲取Bean注解別名或者方法名。
如果聲明 的變量不是以上兩者,則會(huì)報(bào)錯(cuò)
app.getBean()
如果在IOC容器中存在兩個(gè)TestDao實(shí)例,則只能通過(guò)字符串名稱來(lái)獲取bean實(shí)例,如:app.getBean("testDao"),否則無(wú)法獲取到對(duì)象, 有指定@Primary聲明除外。
如果在IOC容器中只存在一個(gè)TestDao實(shí)例,則可以通過(guò)app.getBean(TestDao.class)獲取bean對(duì)象。
@Primary 優(yōu)先
只要Primary出現(xiàn),不管是Autowired 還是getBean取值,都會(huì)優(yōu)先取到 @Primary 聲明的那個(gè)容器對(duì)象實(shí)例,但是,
如果在Autowired中聲明了@Qualifier("testDao"),則在Autowired 上的取值會(huì)優(yōu)先Qualifiler對(duì)象,其他地方還是會(huì)去取Primary對(duì)象
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Springcloud中的Nacos?Config服務(wù)配置流程分析
這篇文章主要介紹了Springcloud中的Nacos?Config服務(wù)配置,本文以用戶微服務(wù)為例,進(jìn)行統(tǒng)一的配置,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09Java中獲取?List中最后一個(gè)元素3種方法以及實(shí)際應(yīng)用
這篇文章主要給大家介紹了關(guān)于Java中獲取?List中最后一個(gè)元素3種方法以及實(shí)際應(yīng)用的相關(guān)資料,由于List的索引是從0開(kāi)始的,所以最后一個(gè)元素的索引是List的大小減1,需要的朋友可以參考下2023-11-11三種SpringBoot中實(shí)現(xiàn)異步調(diào)用的方法總結(jié)
Spring Boot 提供了多種方式來(lái)實(shí)現(xiàn)異步任務(wù),這篇文章主要為大家介紹了常用的三種實(shí)現(xiàn)方式,文中的示例代碼講解詳細(xì),需要的可以參考一下2023-05-05Java異常繼承結(jié)構(gòu)解析_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Java異常繼承結(jié)構(gòu)解析的相關(guān)知識(shí),需要的朋友可以參考下2017-04-04使用JAXBContext 設(shè)置xml節(jié)點(diǎn)屬性
這篇文章主要介紹了使用JAXBContext 設(shè)置xml節(jié)點(diǎn)屬性的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java編程中快速排序算法的實(shí)現(xiàn)及相關(guān)算法優(yōu)化
這篇文章主要介紹了Java編程中快速排序算法的實(shí)現(xiàn)及相關(guān)算法優(yōu)化,快速排序算法的最差時(shí)間復(fù)雜度為(n^2),最優(yōu)時(shí)間復(fù)雜度為(n\log n),存在優(yōu)化的空間,需要的朋友可以參考下2016-05-05Springboot整合Mybatis和SQLite的詳細(xì)過(guò)程
這篇文章主要介紹了Springboot整合Mybatis和SQLite的詳細(xì)過(guò)程,本文通過(guò)圖文示例相結(jié)合給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-07-07Java日期時(shí)間及日期相互轉(zhuǎn)換實(shí)現(xiàn)代碼
這篇文章主要介紹了Java日期時(shí)間及日期相互轉(zhuǎn)換實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12