使用@PropertySource讀取配置文件通過(guò)@Value進(jìn)行參數(shù)注入
@PropertySource讀取配置文件通過(guò)@Value參數(shù)注入
有參數(shù)文件如下test.properties
project.author=wpfc project.create_time=2018/3/29
在系統(tǒng)中讀取對(duì)應(yīng)的數(shù)據(jù),并注入到屬性中
@Configuration @ComponentScan("cn.edu.ntu") @PropertySource("classpath:test.properties") public class ElConfig { ? ?? ?@Value("#{systemProperties['os.name']}") ?? ?private String osName; ?? ? ?? ?//要想使用@Value 用${}占位符注入屬性,這個(gè)bean是必須的(PropertySourcesPlaceholderConfigurer), ? ? //這個(gè)就是占位bean, ?? ?//另一種方式是不用value直接用Envirment變量直接getProperty('key') ? ?? ?@Value("${project.author}") ?? ?public String author; ? ?? ?? ?@Autowired ?? ?private Environment environment; ?? ? ?? ?//You need this if you use @PropertySource + @Value ? ? @Bean ? ? public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { ? ? ? ?return new PropertySourcesPlaceholderConfigurer(); ? ? } ?? ? ?? ?public void printProperties(){ ?? ??? ?System.out.println("os name : " + osName); ?? ??? ?System.out.println("author ?: " + author); ?? ??? ?System.out.println("env ? ? : " + environment.getProperty("project.create_time")); ?? ?}?? ? }
測(cè)試方法:
public class MainApplication { ?? ?public static void main(String[] args){ ?? ??? ?AnnotationConfigApplicationContext context = null; ?? ??? ?context = new AnnotationConfigApplicationContext(ElConfig.class); ?? ??? ?ElConfig bean = context.getBean(ElConfig.class); ?? ??? ?bean.printProperties(); ?? ?}?? ? }
測(cè)試結(jié)果:
os name : Windows 7
author : wpfc
env : 2018/3/29
@Import
引入javaConfig配置的配置類@ImportResource
引入xml對(duì)應(yīng)的配置文件
Spring讀取配置@Value、@PropertySource、@ConfigurationProperties使用
Spring (Boot)獲取參數(shù)的方式有很多,其中最被我們熟知的為@Value了,它不可謂不強(qiáng)大。
今天就針對(duì)我們平時(shí)最長(zhǎng)使用的@Value,以及可能很少人使用的@PropertySource、@ConfigurationProperties等相關(guān)注解進(jìn)行一個(gè)詳細(xì)的掃盲,希望能夠幫助到到家,使用起來(lái)更加順暢
@Value
@Value注解的注入非常強(qiáng)大,可以借助配置文件的注入、也可以直接注入
注入普通字符串
? ? @Value("normal") ? ? private String normal; // normal (顯然這種注入的意義不大)
注入操作系統(tǒng)屬性
@Value("#{systemProperties['os.name']}") ? ? private String systemPropertiesName;? //效果等同于 ?是因?yàn)閟pring模版把系統(tǒng)變量否放進(jìn)了Enviroment @Value("${os.name}") ? ? private String systemPropertiesName;
注入表達(dá)式結(jié)果
@Value("#{ T(java.lang.Math).random() * 100.0 }") ? ? private double randomNumber; //41.29185128620939
注入其它Bean的屬性:Person類的name屬性
? ? @Bean ? ? public Person person() { ? ? ? ? Person person = new Person(); ? ? ? ? person.setName("fangshixiang"); ? ? ? ? return person; ? ? } ? //注入屬性 ? ? @Value("#{person.name}") ? ? private String personName; ? ? ? @Test ? ? public void contextLoads() { ? ? ? ? System.out.println(personName); //fangshixiang ? ? }
注入文件資源
在resources下放置一個(gè)jdbc.properties配置文件。然后可以直接注入
? ? @Value("classpath:jdbc.properties") ? ? private Resource resourceFile; // 注入文件資源 ? ? ? @Test ? ? public void contextLoads() throws IOException { ? ? ? ? System.out.println(resourceFile); //class path resource [jdbc.properties] ? ? ? ? String s = FileUtils.readFileToString(resourceFile.getFile(), StandardCharsets.UTF_8); ? ? ? ? System.out.println(s); ? ? ? ? //輸出: ? ? ? ? //db.username=fangshixiang ? ? ? ? //db.password=fang ? ? ? ? //db.url=jdbc:mysql://localhost:3306/mytest ? ? ? ? //db.driver-class-name=com.mysql.jdbc.Driver ? ? }
注入U(xiǎn)rl資源
? ? @Value("http://www.baidu.com") ? ? private Resource testUrl; // 注入U(xiǎn)RL資源? ? ? ? @Test ? ? public void contextLoads() { ? ? ? ? System.out.println(testUrl); //URL [http://www.baidu.com] ? ? }
@Value中$和#的區(qū)別
語(yǔ)法:
${ properties }和#{ SpEL }的語(yǔ)法區(qū)別
${ property : default_value }
#{ obj.property? : default_value } 表示SpEl表達(dá)式通常用來(lái)獲取bean的屬性,或者調(diào)用bean的某個(gè)方法。當(dāng)然還有可以表示常量
正常使用的情況,這里不做過(guò)多的介紹了,現(xiàn)在介紹一些異常情況
${ properties }`:這種比較簡(jiǎn)單,如果key找不到,啟動(dòng)會(huì)失敗。如果找不到的時(shí)候也希望正常啟動(dòng),可以采用冒號(hào)+默認(rèn)值的方式
#{ obj.property? : default_value }
@Value("#{person}") private Person value; @Test public void contextLoads() { System.out.println(value); //Person(name=fangshixiang, age=null, addr=null, hobby=null) }
我們發(fā)現(xiàn)這個(gè)很強(qiáng)大,可以直接把容器的里的一個(gè)對(duì)象直接注入進(jìn)來(lái)。只是我們可能一般不這么做。
如果改成person1,在容器里找不到這個(gè)bean,也是會(huì)啟動(dòng)報(bào)錯(cuò)的。@Value("#{person1?:null}")這樣也是不行的,因?yàn)閜erson1找不到就會(huì)報(bào)錯(cuò)
@Value("#{person.name}") private String personName; @Value("#{person.age}") private String perAge; //注入默認(rèn)值 @Value("#{person.age?:20}") private String perAgeDefault; //如果age22這個(gè)key根本就不存在,啟動(dòng)肯定會(huì)報(bào)錯(cuò)的 //@Value("#{person.age22?:20}") //private String perAgeDefault22; @Test public void contextLoads() { System.out.println(personName); //fangshixiang System.out.println(perAge); //null System.out.println(perAgeDefault); //20 }
獲取級(jí)聯(lián)屬性,下面兩種方法都是ok的:
@Value("#{person.parent.name}") private String parentName1; @Value("#{person['parent.name']}") private String parentName2; @Test public void contextLoads() { System.out.println(parentName1); //fangshixiang System.out.println(parentName2); //fangshixiang }
二者結(jié)合使用:#{ ‘${}’ }
注意結(jié)合使用的語(yǔ)法和單引號(hào),不能倒過(guò)來(lái)。
兩者結(jié)合使用,可以利用SpEL的特性,寫(xiě)出一些較為復(fù)雜的表達(dá)式,如:
@Value("#{'${os.name}' + '_' + person.name}") private String age; @Test public void contextLoads() { System.out.println(age); //Windows 10_fangshixiang }
@PropertySource:加載配置屬性源
此注解也是非常非常的強(qiáng)大,用好了,可以很好的實(shí)現(xiàn)配置文件的分離關(guān)注,大大提高開(kāi)發(fā)的效率,實(shí)現(xiàn)集中化管理
最簡(jiǎn)單的應(yīng)用,結(jié)合@Value注入屬性值(也是最常見(jiàn)的應(yīng)用)
通過(guò)@PropertySource把配置文件加載進(jìn)來(lái),然后使用@Value獲取
@Configuration @PropertySource("classpath:jdbc.properties") public class PropertySourceConfig { @Value("${db.url}") private String dbUrl; @PostConstruct public void postConstruct() { System.out.println(dbUrl); //jdbc:mysql://localhost:3306/mytest } }
@PropertySource各屬性介紹
value
:數(shù)組。指定配置文件的位置。支持classpath:和file:等前綴 Spring發(fā)現(xiàn)是classpath開(kāi)頭的,因此最終使用的是Resource的子類ClassPathResource。如果是file開(kāi)頭的,則最終使用的類是FileSystemResourceignoreResourceNotFound
:默認(rèn)值false。表示如果沒(méi)有找到文件就報(bào)錯(cuò),若改為true就不報(bào)錯(cuò)。建議保留falseencoding
:加載進(jìn)來(lái)的編碼。一般不用設(shè)置,可以設(shè)置為UTF-8等等factory
:默認(rèn)的值為DefaultPropertySourceFactory.class。
@Override public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { return (name != null ? new ResourcePropertySource(name, resource) : new ResourcePropertySource(resource)); }
源碼其實(shí)也沒(méi)什么特別的。其重難點(diǎn)在于:
1、DefaultPropertySourceFactory什么時(shí)候被Spring加載呢?
2、name和resource都是什么時(shí)候被賦值進(jìn)來(lái)的?
本文拋出這兩個(gè)問(wèn)題,具體原因會(huì)在后續(xù)分析源碼的相關(guān)文章中有所體現(xiàn)。
需要注意的是PropertySourceFactory的加載時(shí)機(jī)早于Spring Beans容器,因此實(shí)現(xiàn)上不能依賴于Spring的IOC。
@PropertySource多環(huán)境配置以及表達(dá)式使用(spring.profiles.active)
方法一:可以這么配置
@PropertySource(“classpath:jdbc-${spring.profiles.active}.properties”)
程序員在開(kāi)發(fā)時(shí)不需要關(guān)心生產(chǎn)環(huán)境數(shù)據(jù)庫(kù)的地址、賬號(hào)等信息,一次構(gòu)建即可在不同環(huán)境中運(yùn)行
@ConfigurationProperties
注意:上面其實(shí)都是Spring Framwork提供的功能。而@ConfigurationProperties是Spring Boot提供的。包括@EnableConfigurationProperties也是Spring Boot才有的。它在自動(dòng)化配置中起到了非常關(guān)鍵的作用
ConfigurationPropertiesBindingPostProcessor會(huì)對(duì)標(biāo)注@ConfigurationProperties注解的Bean進(jìn)行屬性值的配置。
有時(shí)候有這樣子的情景,我們想把配置文件的信息,讀取并自動(dòng)封裝成實(shí)體類,這樣子,我們?cè)诖a里面使用就輕松方便多了,這時(shí)候,我們就可以使用@ConfigurationProperties,它可以把同類的配置信息自動(dòng)封裝成實(shí)體類
該注解在Spring Boot的自動(dòng)化配置中得到了大量的使用
如SpringMVC的自動(dòng)化配置:
@ConfigurationProperties(prefix = "spring.mvc") public class WebMvcProperties {} //加載方式 @Configuration @Conditional(DefaultDispatcherServletCondition.class) @ConditionalOnClass(ServletRegistration.class) // 此處采用這個(gè)注解,可議把WebMvcProperties這個(gè)Bean加載到容器里面去~~~ // WebMvcProperties里面使用了`@ConfigurationProperties(prefix = "spring.mvc")` @EnableConfigurationProperties(WebMvcProperties.class) //加載MVC的配置文件 protected static class DispatcherServletConfiguration {}
似乎我們能看出來(lái)一些該注解的使用方式。
說(shuō)明:這里說(shuō)的兩種,只是說(shuō)的最常用的。其實(shí)只要能往容器注入Bean,都是一種方式,比如上面的@EnableConfigurationProperties方式也是ok的
關(guān)于@EnableConfigurationProperties的解釋,在注解驅(qū)動(dòng)的Spring相關(guān)博文里會(huì)有體現(xiàn)
加在類上,需要和@Component注解,結(jié)合使用.代碼如下
com.example.demo.name=${aaa:hi} com.example.demo.age=11 com.example.demo.address[0]=北京 ?# 注意數(shù)組 List的表示方式 Map/Obj的方式各位可以自行嘗試 com.example.demo.address[1]=上海 com.example.demo.address[2]=廣州 com.example.demo.phone.number=1111111
java代碼:
@Component @ConfigurationProperties(prefix = "com.example.demo") public class People { ? ? ? private String name; ? ? private Integer age; ? ? private List<String> address; ? ? private Phone phone; } ??
通過(guò)@Bean的方式進(jìn)行聲明,這里我們加在啟動(dòng)類即可,代碼如下
? @Bean ? ? @ConfigurationProperties(prefix = "com.example.demo") ? ? public People people() { ? ? ? ? return new People(); ? ? }
此些方式并不需要使用@EnableConfigurationProperties去開(kāi)啟它。
細(xì)節(jié):Bean的字段必須有g(shù)et/set方法,請(qǐng)注意~~~
另外還有一種結(jié)合@PropertySource使用的方式,可謂完美搭配
@Component @PropertySource("classpath:config/object.properties") @ConfigurationProperties(prefix = "obj") public class ObjectProperties {}
其余屬性見(jiàn)名之意,這里一筆帶過(guò):
ignoreInvalidFields
ignoreNestedProperties
ignoreUnknownFields
簡(jiǎn)單理解:
@ConfigurationProperties
是將application配置文件的某類名下所有的屬性值,自動(dòng)封裝到實(shí)體類中。@Value
是將application配置文件中,所需要的某個(gè)屬性值,封裝到j(luò)ava代碼中以供使用。
應(yīng)用場(chǎng)景不同:
如果只是某個(gè)業(yè)務(wù)中需要獲取配置文件中的某項(xiàng)值或者設(shè)置具體值,可以使用@Value;
如果一個(gè)JavaBean中大量屬性值要和配置文件進(jìn)行映射,可以使用@ConfigurationProperties;
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Mybatis-Plus實(shí)現(xiàn)多主鍵批量保存及更新詳情
這篇文章主要介紹了Mybatis-Plus實(shí)現(xiàn)多主鍵批量保存及更新詳情,文章通過(guò)圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09Java用Arrays.asList初始化ArrayList實(shí)例方法
在本篇文章里小編給大家分享的是關(guān)于Java中使用Arrays.asList初始化ArrayList的知識(shí)點(diǎn)內(nèi)容,需要的朋友們參考下。2019-10-10SpringBoot配置log4j2的實(shí)現(xiàn)示例
SpringBoot中默認(rèn)使用Logback作為日志框架,本文主要介紹了SpringBoot配置log4j2的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12使用Java實(shí)現(xiàn)簡(jiǎn)單串口通信
這篇文章主要介紹了使用Java實(shí)現(xiàn)簡(jiǎn)單串口通信,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07微信開(kāi)發(fā)--自定義菜單查詢返碼亂碼的解決方法
本篇文章主要介紹了微信開(kāi)發(fā)--自定義菜單查詢返碼亂碼的解決方法,具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-03-03