詳解SpringBoot依賴注入和使用配置文件
前言
在上一篇文章中,講訴了SpringIoC的Bean裝配,但是對于如何進行獲取,也就是Bean之間的依賴還未講訴,下面開始講訴依賴注入(Dependency Injection,DI)以及如何使用屬性文件。涉及主要注解@Autowired、@Primary、@Quelifier、@PropertySource和@ConfigurationProperties。
一、??依賴注入
例:人類(Person)有時候利用一些動物(Animal)去完成一些事情,比方說狗(Dog)是用來看門的,貓(Cat)是用來抓老鼠的, 鸚鵡(Paηot)是用來迎客的……于是做一些事情就依賴于那些可愛的動物。假設(shè)現(xiàn)在需要用狗狗來看門。
//定義人類接口 public interface Person { void service(); void setAnimal(Animal animal); } //定義動物接口 public interface Animal { void user(); } //定義狗 @Component public class Dog implements Animal { @Override public void user() { System.out.println("狗【" + Dog.class.getSimpleName() + "】是用來看門的"); } } //定義年輕人 @Component public class YoungPerson implements Person { @Autowired private Animal animal = null; @Override public void service() { this.animal.user(); } @Override public void setAnimal(Animal animal) { this.animal = animal; } } //定義配置類 @Configuration @ComponentScan("com.dragon.restart")//所有的包和類都在restart下 public class AppConfig { }
測試類:
ApplicationContext ctx =new AnnotationConfigApplicationContext(AppConfig.class) ; Person person= ctx.getBean(YoungPerson.class) ; person.service() ;
測試是成功的,這個時候SpringIoC 容器己經(jīng)通過注解@Autowired成功地將Dog注入到了 YoungPerson 實例中。 但是這只是一個比較簡單的例子,我們有必要繼續(xù)探討@Autowired。
??注解@Autowired
@Autowired 是我們使用得最多的注解之一, 因此在這里需要進一步地探討它。 它注入的機制最基本的一條是根據(jù)類型 (bytype), 我們回顧IoC 容器的頂級接口 BeanFactory,就可以知道 IoC 容器是通過getBean 方法獲取對應(yīng)Bean 的,而 getBean 又支持根據(jù)類型(by type)或者根據(jù)名稱(by name)。這里明顯根據(jù)類型注入,將狗狗實例注入Animal對象。
再回到上面的例子,我們只是創(chuàng)建了一個動物一一狗,而實際上動物還可以有貓 (Cat),貓可以為我們抓老鼠, 于是我們又創(chuàng)建了一個貓的類。
@Component public class Cat implements Animal{ @Override public void user() { System.out.println("貓【" + Cat.class.getSimpleName() + "】是抓老鼠的"); } }
好了,如果我們還使用著YoungPerson類,那么麻煩來了,因為這個類只是定義了一個動物屬性(Animal),而我們卻有兩個動物,一個狗, 一個貓, SpringIoC 如何注入呢?
運行測試,可以看到IoC容器拋出異常,如下:
Description:
Field animal in com.dragon.restart.pojo.impl.YoungPerson required a single bean, but 2 were found:
- cat: defined in file [E:\IDEA_projects\restart\target\classes\com\dragon\restart\pojo\Cat.class]
- dog: defined in file [E:\IDEA_projects\restart\target\classes\com\dragon\restart\pojo\impl\Dog.class]
那么使用@Autowired 能處理這個問題嗎?答案是肯定的。假設(shè)我們目前需要的是狗提供服務(wù),那么可以把屬性名稱轉(zhuǎn)化為dog,也就是原來YoungPerson的private Animal animal = null;
改為private An工mal dog = null;
@Component public class YoungPerson implements Person { @Autowired private Animal dog = null; @Override public void service() { this.dog.user(); } @Override public void setAnimal(Animal animal) { this.dog = animal; } }
這里, 我們只是將屬性的名稱從animal 修改為了 dog,那么我們再測試的時候,你可以看到是采用狗來提供服務(wù)的。那是因為@Autowired提供這樣的規(guī)則:首先它會根據(jù)類型找到對應(yīng)的Bean,如果對應(yīng)類型的 Bean 不是唯一的,那么它會根據(jù)其屬性名稱和 Bean 的名稱進行匹配。如果匹配得上,就會使用該Bean:如果還無法匹配,就會拋出異常。這里還要注意的是@Autowired 是一個默認必須找到對應(yīng) Bean 的注解,如果不能確定其標注屬性一定會存在并且允許這個被標注的屬性為null, 那么你可以配置@Autowired屬性 required 為 false如@Autowired(required = false)
@Autowired除了可以標注屬性外,還可以標注方法, 如setAnimal方法,如下所示:
@Override @Autowired public void setAnimal (Animal animal) { this.animal = animal;
這樣它也會使用setAnimal 方法從 IoC 容器中找到對應(yīng)的動物進行注入,甚至我們還可以使用在方法的參數(shù)上,后續(xù)文章會再談到它。
??消除歧義性——@Quelifier和@Primary
在上面我們發(fā)現(xiàn)有貓有狗的時候, 為了使@Autowired 能夠繼續(xù)使用,我們做了一個決定,將YoungPerson 的屬性名稱從 animal 修改為 dog。顯然這是一個憋屈的做法,好好的一個動物,卻被我們定義為了狗,畢竟不能每次換個對象就改一次,這樣太麻煩了。產(chǎn)生注入失敗的問題根本是按類型(bytype) 查找, 正如動物可以有多種類型,這樣會造成 Spring IoC 容器注入的困擾,我們把這樣的一個問題稱為歧義性。知道這個原因后, 那么這兩個注解是從哪個角度去解決這些問題的呢?
首先是一個注解@Primary,它是一個修改優(yōu)先權(quán)的注解,當我們有貓有狗的時候,假設(shè)這次需要使用貓, 那么只需要在貓類的定義上加入@Primarγ就可以了,如下:
@Component @Primary public class Dog implements Animal { @Override public void user() { System.out.println("狗【" + Dog.class.getSimpleName() + "】是用來看門的"); } }
這里的@Primary 的含義告訴 Spring IoC 容器, 當發(fā)現(xiàn)有多個同樣類型的 Bean 時,請優(yōu)先使用我進行注入,于是再進行測試時會發(fā)現(xiàn),系統(tǒng)將用狗狗為你提供服務(wù)。 因為當 Spring 進行注入的時候,雖然它發(fā)現(xiàn)存在多個動物, 但因為Dog被標注為了@Primarγ,所以優(yōu)先采用Dog的實例進行了注入,這樣就通過優(yōu)先級的變換使得IoC容器知道注入哪個具體的實例來滿足依賴注入。然后,有時候@Primary 也可以使用在多個類上,也許無論是貓還是狗狗都可能帶上@Primary 注解, 其結(jié)果是IoC容器還是無法區(qū)分采用哪個Bean的實例進行注入, 又或者說我們需要更加靈活的機制來實現(xiàn)注入,那么**@Quelifier** 可以滿足你的這個愿望。
它將與@Autowired 組合在一起,通過類型和名稱一起找到Bean。我們知道Bean 名稱在 Spring IoC 容器中是唯一的標識,通過這個就可以消除歧義性了。此時你是否想起了BeanFactory接口中的這個方法呢?<T> T getBean(String name, Class<T> requiredType) throws BeansException;
代碼:
@Component public class YoungPerson implements Person { @Autowired @Qualifier("dog") private Animal animal = null; @Override public void service() { this.animal.user(); } @Override public void setAnimal(Animal animal) { this.animal = animal; } }
一旦這樣聲明, Spring IoC 將會以類型和名稱去尋找對應(yīng)的Bean進行注入。根據(jù)類型和名稱,顯然也只能找到狗狗為我們服務(wù)了。
??帶有參數(shù)的構(gòu)造方法類裝配
在上面,我們都基于一個默認的情況,那就是不帶參數(shù)的構(gòu)造方法下實現(xiàn)依賴注入。但事實上,有些類只有帶有參數(shù)的構(gòu)造方法,于是上述的方法都不能再使用了。為了滿足這個功能,我們可以使用@Autowired 注解對構(gòu)造方法的參數(shù)進行注入,例如,修改類YoungPerson來滿足這個功能。
database.driverName=com.mysql.jdbc.Driver database.url=jdbc:mysql://localhost:3306/my database.username=root database.password=root
@Autowired 和@Qualifier 注解,使其注入進來。這里使用@Qualifier 是為了避免歧義性。當然如果你的環(huán)境中不是有貓有狗,則可以完全不使用@Qualifier,而單單使用@Autowired就可以了。
二、??使用屬性文件
Java 開發(fā)使用屬性文件已經(jīng)十分普遍,所以這里談?wù)勥@方面的內(nèi)容。在Spring Boot 中使用屬性文件,可以采用其默認為我們準備的application.properties,也可以使用自定義的配置文件。 應(yīng)該說讀取配置文件的方法很多, 這里沒有必要面面俱到地介紹每一個細節(jié),只是介紹那些最常用的方法。
在SpringBoot項目的application.properties:
/** * @Version: 1.0.0 * @Author: Dragon_王 * @ClassName: DataBaseProperties * @Description: TODO描述 * @Date: 2024/1/16 16:07 */ @Component public class DataBaseProperties { @Value("${database.driverName}") private String driverName = null; @Value("${database.url}") private String url = null; private String username = null; private String password = null; public void setDriverName(String driverName) { System.out.println(driverName); this.driverName = driverName; } public void setUrl(String url) { System.out.println(url); this.url = url; } @Value("${database.username}") public void setUsername(String username) { System.out.println(username); this.username = username; } @Value("${database.password}") public void setPassword(String password) { System.out.println(password); this.password = password; } public String getDriverName() { return driverName; } public String getUrl() { return url; } public String getUsername() { return username; } public String getPassword() { return password; } }
創(chuàng)建個DataBaseProperties類:
/** * @Version: 1.0.0 * @Author: Dragon_王 * @ClassName: DataBaseProperties * @Description: TODO描述 * @Date: 2024/1/16 16:07 */ @Component public class DataBaseProperties { @Value("${database.driverName}") private String driverName = null; @Value("${database.url}") private String url = null; private String username = null; private String password = null; public void setDriverName(String driverName) { System.out.println(driverName); this.driverName = driverName; } public void setUrl(String url) { System.out.println(url); this.url = url; } @Value("${database.username}") public void setUsername(String username) { System.out.println(username); this.username = username; } @Value("${database.password}") public void setPassword(String password) { System.out.println(password); this.password = password; } public String getDriverName() { return driverName; } public String getUrl() { return url; } public String getUsername() { return username; } public String getPassword() { return password; } }
通過@Value注解, 使用${… }這樣的占位符讀取配置在屬性文件的內(nèi)容。這里的@Value 注解,既可以加載屬性, 也可以加在方法上。
這樣就能成功將屬性文件內(nèi)容成功注入了。但是我們可以使用過注解@ConfigurationProperties來簡化一下,同樣能實現(xiàn)注入,如下:
/** * @Version: 1.0.0 * @Author: Dragon_王 * @ClassName: DataBaseProperties * @Description: TODO描述 * @Date: 2024/1/16 16:07 */ @Component @ConfigurationProperties("database") public class DataBaseProperties { private String driverName = null; private String url = null; private String username = null; private String password = null; public void setDriverName(String driverName) { System.out.println(driverName); this.driverName = driverName; } public void setUrl(String url) { System.out.println(url); this.url = url; } public void setUsername(String username) { System.out.println(username); this.username = username; } public void setPassword(String password) { System.out.println(password); this.password = password; } public String getDriverName() { return driverName; } public String getUrl() { return url; } public String getUsername() { return username; } public String getPassword() { return password; } }
這里@ConfigurationProperties注解內(nèi)的database將會與屬性名組成屬性的全限定名去配置文件里查找,如屬性driveName就會和database組成database.driverName去查找,這里注意一下不需要管字母的大小寫,不影響。
如果我不用默認的application.properties文件怎么辦呢?現(xiàn)在我們重新創(chuàng)建一個jdbc.properties文件,將原配置文件內(nèi)容移入其中。
DataBaseProperties 類不變?nèi)缟希瑔宇惻渲萌缦拢?/p>
@SpringBootApplication @PropertySource(value = {"classpath:jdbc.properties"},ignoreResourceNotFound = true) public class RestartApplication { public static void main(String[] args) { SpringApplication.run(RestartApplication.class, args); } }
value 可以配置多個配置文件。使用 classpath 前綴, 意味著去類文件路徑下找到屬性文件;ignoreResourceNotFound 則是是否忽略配置文件找不到的問題。 ignoreResourceNotFound 的默認值為false,也就是沒有找到屬性文件, 就會報錯;這里配置為true,也就是找不到就忽略掉,不會報錯。通過運行日志,可以看出成功注入。
總結(jié)
以上就是依賴注入和使用配置配置文件的講解,歡迎大家一起討論。
到此這篇關(guān)于詳解SpringBoot依賴注入和使用配置文件的文章就介紹到這了,更多相關(guān)SpringBoot依賴注入和配置文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot2.0以上調(diào)度器配置線程池的實現(xiàn)
這篇文章主要介紹了springboot2.0以上調(diào)度器配置線程池的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-12-12解決Mybatis中foreach嵌套使用if標簽對象取值的問題
這篇文章主要介紹了解決Mybatis中foreach嵌套使用if標簽對象取值的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02SpringBoot?Security使用MySQL實現(xiàn)驗證與權(quán)限管理
安全管理是軟件系統(tǒng)必不可少的的功能。根據(jù)經(jīng)典的“墨菲定律”——凡是可能,總會發(fā)生。如果系統(tǒng)存在安全隱患,最終必然會出現(xiàn)問題,這篇文章主要介紹了SpringBoot安全管理Spring?Security基本配置2022-11-11現(xiàn)代高效的java構(gòu)建工具gradle的快速入門
和Maven一樣,Gradle只是提供了構(gòu)建項目的一個框架,真正起作用的是Plugin,本文主要介紹了gradle入門,文中通過示例代碼介紹的非常詳細,感興趣的小伙伴們可以參考一下2021-11-11springboot多文件上傳實現(xiàn)使用postman測試多文件上傳接口
這篇文章主要介紹了springboot多文件上傳實現(xiàn)使用postman測試多文件上傳接口,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08SpringBoot之spring.factories的使用方式
這篇文章主要介紹了SpringBoot之spring.factories的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01springboot 整合EhCache實現(xiàn)單服務(wù)緩存的操作方法
這篇文章主要介紹了springboot 整合EhCache實現(xiàn)單服務(wù)緩存的操作方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07