SpringBoot注入自定義的配置文件的方法詳解
一、簡介
在實際的項目開發(fā)過程中,我們經(jīng)常需要將某些變量從代碼里面抽離出來,放在配置文件里面,以便更加統(tǒng)一、靈活的管理服務配置信息。比如,數(shù)據(jù)庫、eureka、zookeeper、redis、mq、kafka 等服務組件的連接參數(shù)配置,還有我們自定義的項目參數(shù)配置變量。
當然,實際上根據(jù)當前的業(yè)務需求,我們往往會自定義參數(shù),然后注入到代碼里面去,以便靈活使用!
今天,我們就一起來聊一聊SpringBoot
加載配置文件的幾種玩法,如果有遺漏,歡迎留言!
SpringBoot 項目在啟用時,首先會默認加載bootstrap.properties
或者bootstrap.yml
這兩個配置文件(這兩個優(yōu)先級最高);接著會加載application.properties
或application.yml
;如果何配置了spring.profiles
這個變量,同時還會加載對應的application-{profile}.properties
或者application-{profile}.yml
文件,profile
為對應的環(huán)境變量,比如dev
,如果沒有配置,則會加載profile=default
的配置文件。
雖然說配置項都寫在同一個配置文件沒有問題,但是很多時候我們?nèi)匀幌M芊珠_寫,這樣會比較清晰,比如zookeeper
的配置寫在zookeeper.properties
,數(shù)據(jù)庫相關的配置寫在datasource.properties
等等,因此就需要設置加載外部配置文件!
具體該如何實現(xiàn)呢,我們一起來看看!
二、代碼實踐
2.1 通過@value注解實現(xiàn)參數(shù)加載
當我們想要在某個類里面注入某個變量,通過@value
注解就可以簡單實現(xiàn)參數(shù)的注入!
例如application.properties
文件里,配置一個config.name
的變量key
,值為zhangsan
//參數(shù)定義 config.name=zhangsan
然后在對應的類里面,通過參數(shù)@value
注入即可!
@RestController public?class?HelloController?{ ???? ????@Value("${config.name}") ????private?String?config; ????@GetMapping("config") ????public?String?config(){ ????????return?JSON.toJSONString(config); ????} }
使用@value
注解注入配置,通常情況下有個要求就是,注解里面的變量,必須在application.properties
文件里面事先定義好,否則啟動報錯!
當然,如果我們不想讓它抱錯,我們可以給它一個缺省值xxx
,比如:
@Value("${config.name:xxx}") private?String?config;
這樣,SpringBoot 項目在啟用時不會報錯!
2.2 通過@ConfigurationProperties注解實現(xiàn)參數(shù)加載
某些場景下,@value
注解并不能滿足我們所有的需求,比如參數(shù)配置的數(shù)據(jù)類型是一個對象或者數(shù)組,這個時候才用@ConfigurationProperties
會是一個比較好的選擇!
配置一個對象類型的參數(shù)
例如在application.properties
文件里,當我們想配置一個對象類型的參數(shù),我們可以這樣操作!
//參數(shù)定義 config2.name=demo_1 config2.value=demo_value_1
然后,創(chuàng)建一個配置類Config2
,用于將定義的變量映射到配置類里面。
@Component @ConfigurationProperties(prefix?=?"config2") public?class?Config2?{ ????public?String?name; ????public?String?value; ????//...get、set }
讀取數(shù)據(jù)的方式,也很簡單,直接注入到對應的類里面就可以了
@RestController public?class?HelloController?{ ???? ????@Autowired ????private?Config2?config2; ????@GetMapping("config2") ????public?String?config2(){ ????????return?JSON.toJSONString(config2); ????} }
配置一個Map類型的參數(shù)
例如在application.properties
文件里,當我們想配置一個 Map 類型的參數(shù),我們可以這樣操作!
//參數(shù)定義 config3.map1.name=demo_id_1_name config3.map1.value=demo_id_1_value config3.map2.name=demo_id_2_name config3.map2.value=demo_id_2_value
然后,創(chuàng)建一個配置類Config3
,用于將定義的變量映射到配置類里面。
@Component @ConfigurationProperties(prefix?=?"config3") public?class?Config3?{ ????private?Map<String,?String>?map1?=?new?HashMap<>(); ????private?Map<String,?String>?map2?=?new?HashMap<>(); ????//...get、set }
讀取數(shù)據(jù)的方式,與之類似!
@RestController public?class?HelloController?{ ???? ????@Autowired ????private?Config3?config3; ????@GetMapping("config3") ????public?String?config3(){ ????????return?JSON.toJSONString(config3); ????} }
配置一個List類型的參數(shù)
例如在application.properties
文件里,當我們想配置一個 List 類型的參數(shù),我們可以這樣操作!
//參數(shù)定義 config4.userList[0].enable=maillist_1_enable config4.userList[0].name=maillist_1_name config4.userList[0].value=maillist_1_value config4.userList[1].enable=maillist_2_enable config4.userList[1].name=maillist_2_name config4.userList[1].value=maillist_2_value config4.userList[2].enable=maillist_3_enable config4.userList[2].name=maillist_3_name config4.userList[2].value=maillist_3_value
然后,創(chuàng)建一個配置類Config4
,用于將定義的變量映射到配置類里面。
@Component @ConfigurationProperties(prefix?=?"config4") public?class?Config4?{ ????private?List<UserEntity>?userList; ????public?List<UserEntity>?getUserList()?{ ????????return?userList; ????} ????public?void?setUserList(List<UserEntity>?userList)?{ ????????this.userList?=?userList; ????} }
public?class?UserEntity?{ ????private?String?enable; ????private?String?name; ????private?String?value; ????//...get、set }
讀取數(shù)據(jù)的方式,與之類似!
@RestController public?class?HelloController?{ ???? ????@Autowired ????private?Config4?config4; ????@GetMapping("config4") ????public?String?config4(){ ????????return?JSON.toJSONString(config4); ????} }
2.3 通過@PropertySource注解實現(xiàn)配置文件加載
正如我們最開始所介紹的,很多時間,我們希望將配置文件分卡寫,比如zookeeper
組件對應的服務配置文件是zookeeper.properties
,redis
組件對應的服務配置文件是redis.properties
等等。
這種自定義的配置文件,我們應該如何加載到Spring
容器里面呢?
其實方法也很簡單,通過@PropertySource
就可以實現(xiàn)!
首先,我們在resources
資源文件夾下,創(chuàng)建兩個配置文件test.properties
和bussiness.properties
,內(nèi)容如下!
test.properties
文件內(nèi)容:
aaa.a1=aa1123 aaa.a2=aa2123 aaa.a3=aa3123 aaa.a4=aa4123
bussiness.properties
文件內(nèi)容:
bbbb.a1=bb1123 bbbb.a2=bb2123 bbbb.a3=bb3123 bbbb.a4=bb4123
在SpringBoot
啟動類上加載配置文件即可!
@SpringBootApplication @PropertySource(value?=?{"test.properties","bussiness.properties"}) public?class?PropertyApplication?{ ????public?static?void?main(String[]?args)?{ ????????SpringApplication.run(PropertyApplication.class,?args); ????} }
讀取數(shù)據(jù)的方式,與之類似!
@RestController public?class?HelloController?{ ???? ????@Value("${aaa.a2}") ????private?String?a2; ????@Value("${bbbb.a1}") ????private?String?bbbbA1; ???? ????@GetMapping("a2") ????public?String?a2(){ ????????return?JSON.toJSONString(a2); ????} ????@GetMapping("bbbbA1") ????public?String?bbbbA1(){ ????????return?JSON.toJSONString(bbbbA1); ????} }
如果我們只是在業(yè)務中需要用到自定義配置文件的值,這樣引入并沒有什么問題;但是如果某些自定義的變量,在項目啟動的時候需要用到,這種方式會存在一些問題,原因如下:
翻譯過來的意思就是說:
雖然在@SpringBootApplication
上使用@PropertySource
似乎是在環(huán)境中加載自定義資源的一種方便而簡單的方法,但我們不推薦使用它,因為SpringBoot
在刷新應用程序上下文之前就準備好了環(huán)境。使用@PropertySource
定義的任何鍵都加載得太晚,無法對自動配置產(chǎn)生任何影響。
因此,如果某些參數(shù)是啟動項變量,建議將其定義在application.properties
或application.yml
文件里面,這樣就不會有問題!
或者,采用【自定義環(huán)境處理類】來實現(xiàn)配置文件的加載!
2.4 通過自定義環(huán)境處理類,實現(xiàn)配置文件的加載
實現(xiàn)方法也很簡單,首先,創(chuàng)建一個實現(xiàn)自EnvironmentPostProcessor
接口的類,然后自行加載配置文件。
public?class?MyEnvironmentPostProcessor?implements?EnvironmentPostProcessor?{ ????@Override ????public?void?postProcessEnvironment(ConfigurableEnvironment?environment,?SpringApplication?application)?{ ????????//自定義配置文件 ????????String[]?profiles?=?{ ????????????????"test.properties", ????????????????"bussiness.properties", ????????????????"blog.yml" ????????}; ????????//循環(huán)添加 ????????for?(String?profile?:?profiles)?{ ????????????//從classpath路徑下面查找文件 ????????????Resource?resource?=?new?ClassPathResource(profile); ????????????//加載成PropertySource對象,并添加到Environment環(huán)境中 ????????????environment.getPropertySources().addLast(loadProfiles(resource)); ????????} ????} ????//加載單個配置文件 ????private?PropertySource<?>?loadProfiles(Resource?resource)?{ ????????if?(!resource.exists())?{ ????????????throw?new?IllegalArgumentException("資源"?+?resource?+?"不存在"); ????????} ????????if(resource.getFilename().contains(".yml")){ ????????????return?loadYaml(resource); ????????}?else?{ ????????????return?loadProperty(resource); ????????} ????} ????/** ?????*?加載properties格式的配置文件 ?????*?@param?resource ?????*?@return ?????*/ ????private?PropertySource?loadProperty(Resource?resource){ ????????try?{ ????????????//從輸入流中加載一個Properties對象 ????????????Properties?properties?=?new?Properties(); ????????????properties.load(resource.getInputStream()); ????????????return?new?PropertiesPropertySource(resource.getFilename(),?properties); ????????}catch?(Exception?ex)?{ ????????????throw?new?IllegalStateException("加載配置文件失敗"?+?resource,?ex); ????????} ????} ????/** ?????*?加載yml格式的配置文件 ?????*?@param?resource ?????*?@return ?????*/ ????private?PropertySource?loadYaml(Resource?resource){ ????????try?{ ????????????YamlPropertiesFactoryBean?factory?=?new?YamlPropertiesFactoryBean(); ????????????factory.setResources(resource); ????????????//從輸入流中加載一個Properties對象 ????????????Properties?properties?=?factory.getObject(); ????????????return?new?PropertiesPropertySource(resource.getFilename(),?properties); ????????}catch?(Exception?ex)?{ ????????????throw?new?IllegalStateException("加載配置文件失敗"?+?resource,?ex); ????????} ????} }
接著,在resources
資源目錄下,我們還需要創(chuàng)建一個文件META-INF/spring.factories
,通過spi
方式,將自定義環(huán)境處理類加載到Spring
處理器里面,當項目啟動時,會自動調用這個類!
#啟用我們的自定義環(huán)境處理類 org.springframework.boot.env.EnvironmentPostProcessor=com.example.property.env.MyEnvironmentPostProcessor
這種自定義環(huán)境處理類方式,相對會更佳靈活,首先編寫一個通用的配置文件解析類,支持properties
和yml
文件的讀取,然后將其注入到Spring
容器里面,基本上可以做到一勞永逸!
2.5 最后,我們來介紹一下yml文件讀取
在上文中,我們大部分都是以properties
為案例進行介紹,可能有的人已經(jīng)踩過坑了,在項目中使用@PropertySource
注解來加載yml
文件,結果啟動直接報錯,原因是@PropertySource
不支持直接解析yml
文件,只能解析properties
文件。
那如果,我想單獨解析yml文件,也不想弄一個【自定義環(huán)境處理類】這種方式來讀取文件,應該如何處理呢?
操作方式也很簡單,以自定義的blog.yml
文件為例!
blog.yml
文件內(nèi)容:
pzblog: ??name:?helloWorld
然后,創(chuàng)建一個讀取yml
文件的配置類
@Configuration public?class?ConfigYaml?{ ????/** ?????*?加載YML格式自定義配置文件 ?????*?@return ?????*/ ????@Bean ????public?static?PropertySourcesPlaceholderConfigurer?properties()?{ ????????PropertySourcesPlaceholderConfigurer?configurer?=?new?PropertySourcesPlaceholderConfigurer(); ????????YamlPropertiesFactoryBean?yaml?=?new?YamlPropertiesFactoryBean(); ????????yaml.setResources(new?ClassPathResource("blog.yml")); ????????configurer.setProperties(yaml.getObject()); ????????return?configurer; ????} }
讀取數(shù)據(jù)的方式,與之類似!
@RestController public?class?HelloController?{ ???? ????@Value("${pzblog.name}") ????private?String?pzblogName; ????@GetMapping("pzblogName") ????public?String?pzblogName(){ ????????return?JSON.toJSONString(pzblogName); ????} }
以上就是SpringBoot注入自定義的配置文件的方法詳解的詳細內(nèi)容,更多關于SpringBoot注入配置文件的資料請關注腳本之家其它相關文章!
相關文章
spring Mvc配置xml使ResponseBody返回Json的方法示例
這篇文章主要給大家介紹了關于spring Mvc配置xml使ResponseBody返回Json的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-04-04javascript與jsp發(fā)送請求到servlet的幾種方式實例
本文分別給出了javascript發(fā)送請求到servlet的5種方式實例與 jsp發(fā)送請求到servlet的6種方式實例2018-03-03LeetCode -- Path Sum III分析及實現(xiàn)方法
這篇文章主要介紹了LeetCode -- Path Sum III分析及實現(xiàn)方法的相關資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-10-10Springboot事件和bean生命周期執(zhí)行機制實例詳解
這篇文章主要介紹了Springboot事件和bean的生命周期執(zhí)行機制,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03SpringBoot使用hutool-captcha實現(xiàn)驗證碼生成與驗證
在springboot的登陸頁面中為了防止機器大規(guī)模注冊,機器暴力破解數(shù)據(jù)密碼等危害,需要驗證隨機生成的驗證碼,本文主要介紹了SpringBoot使用hutool-captcha實現(xiàn)驗證碼生成與驗證,感興趣的可以了解一下2023-12-12