Spring核心——資源數據管理

Profile管理環境一文中介紹了環境的概念以及Spring Profile特性控制Bean的添加。本文將進一步介紹Spring管理和控制操做系統變量、JVM變量和Java標準資源(properties文件)的相關功能。html

文章的代碼僅僅用於說明問題,可執行代碼請到個人gitee庫clone,本文的代碼在chkui.springcore.example.hybrid.propertsource包中。java

PropertySource與優先級

在整個Jvm運行期間,咱們能夠隨時隨地獲取到2個與環境相關的參數:git

package chkui.springcore.example.hybrid.propertsource;

//env是與操做系統相關的參數
Map<String, String> env = System.getenv();
//properties中是Jvm相關的參數
Properties p = System.getProperties();
System.out.println("env :" + env);
System.out.println("properties :" +  p);

若是沒有人爲的添加額外信息,System::getEnv獲取的數據都與當前的操做系統相關(如下稱爲「操做系統參數」),而System::getProperties獲取的內容都與Jvm相關(如下稱爲「JVM參數」)。spring

Spring會將操做系統參數和Jvm參數都整合到本身的環境管理接口Environment中,例以下面的代碼:api

package chkui.springcore.example.hybrid.propertsource;

//向系統級的properties設置一個參數
System.setProperty("wow", "World of Warcraft");
ApplicationContext ctx = new AnnotationConfigApplicationContext(PropertySourcesApp.class);
//經過spring的Environment獲取參數
Environment springEnv = ctx.getEnvironment();
System.out.println(springEnv.getProperty("wow"));
System.out.println(springEnv.getProperty("PATH"));

除了咱們自定義的"wow",操做系統參數"PATH"也能夠在Spring的Environment中獲取。bash

一般狀況下,在Environment內部維護了2個PropertySources的實例:一個是操做系統參數,另一個是JVM參數。若是2者有一樣的參數,那麼咱們在調用Environment::getProperty方法時,獲得的是JVM參數(System::getProperties),也就是說 Jvm參數具備更高的優先級。app

除了經過外部設置,咱們也能夠直接使用Spring提供的接口來設置:post

package chkui.springcore.example.hybrid.propertsource;

//咱們要對環境進行配置,須要使用ConfigurableApplicationContext接口
ConfigurableApplicationContext configAbleCtx = new AnnotationConfigApplicationContext(PropertySourcesApp.class);

//ConfigurableApplicationContext接口提供對應的可編輯Environment和PropertySources
MutablePropertySources ps = configAbleCtx.getEnvironment().getPropertySources();
Map<String, Object> map = new HashMap<String, Object>();
map.put("wow", "Origin = World of Warcraft!But Edit it already!");
//添加到Spring的環境參數中
ps.addFirst(new MapPropertySource("myPropertySource", map));
System.out.println(springEnv.getProperty("wow"));

代碼添加到PropertySource中,Environment會額外維護一個PropertySources,而本身添加的PropertySources優先級是最高的,因此最後Environment::getProperty獲取到的值是最後設置的值。ui

若是須要添加多個PropertySources,能夠經過MutablePropertySources::addFirstMutablePropertySources::addLast方法來控制他們之間的優先級。spa

引入資源文件

*.properties是Java的標準資源文件,在Java的各類項目中經常使用來記錄各類配置參數。Spring提供了註解和XML配置將*.properties文件中的數據整合到Spring的環境參數(Environment)中。

@PropertySource

@Configuration標記的類上使用@PropertySource註解能夠引入0~n個*.properties配置文件。以下面的例子:

package chkui.springcore.example.hybrid.propertsource;

@Configuration
@PropertySource("classpath:/hybrid/propertysource/config.properties")
public class PropertySourcesApp {
	public static void main(String[] args) {
		ApplicationContext ctx = new AnnotationConfigApplicationContext(PropertySourcesApp.class); 
		System.out.println("Properties file params: " + springEnv.getProperty("Gdi"));
	}
}

對應的config.properties文件:

#hybrid.propertysource.config.properties

Gdi=StarCraft

同一個工程中支持使用多個@PropertySource註解來引入配置文件,也支持Ant風格(Ant-style,例如"classpath:a/b/**/config.properties")以及Spring擴展的(好比"classpath*:")的路徑規則,資源路徑控制會在後續的文章中介紹。

XML配置

XML配置在以前介紹容器後置處理器——BeanFactoryPostProcessor的文章中已經介紹了,他就是 PropertyPlaceholderConfigurer ,咱們在XML配置文件中進行一下設置便可。

引入Bean:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <!-- 指定*.properties文件的路徑 -->
    <property name="locations" value="classpath:/hybrid/propertysource/config.properties"/>
</bean>

直接使用context進行全局設置:

<context:property-placeholder location="classpath:/hybrid/propertysource/config.properties"/>

佔位符替換

PropertyPlaceholderConfigurer繼承了抽象類PropertyPlaceholderConfigurer,*.properties文件的讀寫就是在PropertyResourceConfigurer類中實現的。PropertyPlaceholderConfigurer進一步實現了配置文件中佔位符(${...})替換功能

在Spring IoC容器執行Bean的掃描、加載以前添加一個環境變量(也能夠動態添加而後再執行ConfigurableApplicationContext::refresh方法),就能夠在不少資源路徑的位置使用這個佔位符,對上面的例子進行一些修改:

@Configuration
//經過佔位符來設置路徑
@PropertySource("classpath:${resource.propertiesPath}/config.properties")
public class PropertySourcesApp {
	public static void main(String[] args) {
        //容器啓動以前設置環境變量
		System.setProperty("resource.propertiesPath", "/hybrid/propertysource");
		ApplicationContext ctx = new AnnotationConfigApplicationContext(PropertySourcesApp.class);
		//獲取環境對象實例
		Environment springEnv = ctx.getEnvironment();
		System.out.println("Properties : " + springEnv.getProperty("Gdi"));
	}
}

一樣的,只要環境變量存在,也可使用佔位符替換配置文件中的數據,例如:

<context:property-placeholder location="classpath:${resource.propertiesPath:/config}/config.properties"/>

XML中的佔位符使用的格式是${resource.propertiesPath:/config},它表示使用環境變量resource.propertiesPath進行替換,若是resource.propertiesPath不存在則使用值"/config"。

@Value

咱們能夠在任何Bean中使用@Value註解來獲取環境變量。以下面的例子:

package chkui.springcore.example.hybrid.propertsource;

@Configuration
public class PropertySourcesApp {
	@Value("${resource.propertiesPath}")
	private String value;
	@Value("#{systemProperties['resource.propertiesPath']}")
	private String elValue;
	@Value("Resource PropertiesPath")
	private String staticValue;
	
	public static void main(String[] args) {
		System.setProperty("resource.propertiesPath", "/hybrid/propertysource");

		ApplicationContext ctx = new AnnotationConfigApplicationContext(PropertySourcesApp.class);
		
		PropertySourcesApp app = ctx.getBean(PropertySourcesApp.class);
		System.out.println("Value: " + app.value);
		System.out.println("EL Value: " + app.elValue);
		System.out.println("Static Value: " + app.staticValue);
	}
}

@Value能夠注入一個純字面量,如上面示例代碼中的staticValue,也可使用佔位符使用環境變量中的任何值。除了使用佔位符${},@Value還支持"#{systemProperties['resource.propertiesPath']}"這樣具有代碼執行功能的複雜表達式來獲取數據,這部分功能會在後續介紹EL表達式的文章中進行分享。

相關文章
相關標籤/搜索