前言
本文我們來看看在Spring中如何使用@PropertySource和@Value注解從屬性文件讀取值,同時呢我們也將討論有關Spring Environment接口的信息以及相應的XML配置。@PropertySource注解主要使用Spring的Environment接口從屬性文件中讀取,事實上,此注解位於@Configuration類上,而 Spring @Value注解可用於在字段或方法上指定表達式,常見的例子是從.properties文件中指定屬性以及默認值,接下來我們一起來看看。
@PropertySource和@Value注解
首先我們在resources文件夾下創建一個名為config.properties的文件,內容如下:
接下來我們在上一節所創建的SpringConfig配置文件中添加一個name字段,如下:
package com.demo.springboot; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @Configuration @PropertySource(value = "classpath:config.properties") public class SpringConfig { @Value("${name}") public String name; @Bean public UserDAL getUserDAL() { System.out.println(name); return new UserDAL(); } }
我們通過@PropertySource注解聲明配置文件存放的地方,一般來講如果是內部配置文件約定是放在spring默認為我們創建的resources文件夾下,當然我們也可以在此文件夾下創建目錄,同時更改注解存放的地址即可。如果要讀取的值存放到內部不同文件夾或者內部和外部,此時我們需要使用@PropertySources,要是讀取的多個配置文件中對應的鍵一樣,此時會以最后讀取的配置文件中的值進行覆蓋,比如如下b配置文件中也存在name,那么配置文件中的值將覆蓋a配置文件中的值。
@PropertySources({@PropertySource("classpath:a.properties"),@PropertySource("classpath:b.properties")})
我們通過注解@Value來讀取找到的配置文件中的值,其中$符號相信我們都不陌生,起到占位符的作用。此時我們不禁想,要是指定配置文件不存在或者找到的配置文件中的值和聲明注解的占位符不匹配會怎樣呢?下面我們將我們創建的配置文件中的name修改為如下名稱,此時將拋出如下異常:
name11=Jeffcky
同理對於配置文件中未查找到,那更加值也將不存在也會拋出如上異常,由於映射值是交給spring內置在處理,我們可能完全捕捉不到這種異常,所以為了解決映射出現異常情況,我們需要給個默認值,對name字段進行如下修改:
@Value("${name:}") public String name;
在占位符中通過冒號指定若映射值不存則使用上述默認空字符串,很完美的解決了這個問題,此時我們打印出如下空字符串
在開頭我們講解到注解@PropertySource是添加到了Spring Environment接口中,所以我們可以從Spring IOC容器中獲取該接口,同樣也可以獲取上述name值,如下:
package com.demo.springboot; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; @Configuration @PropertySource(value = "classpath:config.properties") public class SpringConfig {
@Autowired private Environment environment; @Bean public UserDAL getUserDAL() { System.out.println(environment.getProperty("name")); return new UserDAL(); } }
上述我們講解了映射的占位符不匹配的問題,要是映射的占位符找到了,但是值的類型不匹配該咋辦呢?比如如下,將拋出異常:
org.springframework.beans.factory.UnsatisfiedDependencyException: Cannot convert value of type 'java.lang.String' to required type 'com.sun.org.apache.xpath.internal.operations.String'.....
當然上述情況是及其不可能發生的,我是手賤搞了快捷方式看都沒看,發現也是字符串怎么會拋出如上異常,搞了一會才發現導入的包搞錯了。要是我們將配置文件中name修改為1.0,同時我們將字段name類型修改為int,此時會怎樣呢?
Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "1.0"
此時將出現映射類型不匹配的情況,首先確認到底是映射類型是否為int,若是將配置文件中類型修改1,或者進行如下修改:
@Value("#{new Double('${name}')}") public int name;
或者
@Value("#{T(Double).parseDouble('${name}')}") public int name;
否則將字段類型修改為double(當然包裝類型也可)。如下:
@Value("${name}") public double name;
如上我們一直討論的是將配置文件放在spring resources目錄下,要是我們現在將上述配置文件放在其他目錄(外部目錄)呢,比如如下:
org.springframework.beans.factory.BeanDefinitionStoreException:...... class path resource [config.properties] cannot be opened because it does not exist
對於內部目錄即放在resources目錄下,聲明注解@PropertySource時參數使用classpath,而對於外部目錄聲明注解@PropertySource時參數使用file。如下:
@PropertySource(value = "file:../../config.properties")
此時我們發現同樣會拋出異常,只不過內容不一樣而已。這是因為無論是將文件放在內外部,路徑必須絕對路徑而非相對路徑,只不過將文件放在內部默認目錄是resources而已。
org.springframework.beans.factory.BeanDefinitionStoreException: ....... nested exception is java.io.FileNotFoundException: ..\..\config.properties (系統找不到指定的文件。)
針對Windows系統而言,我們可使用定義環境變量來解決,這里需要注意,定義完環境變量后,此時需要重啟idea才能重新加載系統定義的環境變量,否則不生效,如下:
@PropertySource(value = "file:${Test}/config.properties")
總結
本文我們詳細講解了@PropertySource和@Value注解,針對讀取外部配置文件其實還有一些細節需要深入,這里並未過多深討,等待哪天再次有了更多積累會進一步分析,好了,感謝閱讀本文的您,我們下節見。