Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html
Spring 3.1 提供了新的屬性管理 API,並且功能很是強大且很完善,對於一些屬性配置信息都應該使用新的 API 來管理。位於 org.springframework.core.env
包內。java
Spring Environment 屬性配置管理系列文章:web
PropertySource
:屬性源,key-value 屬性對抽象,好比用於配置數據PropertyResolver
:屬性解析器,用於解析相應 key 的 valueEnvironment
:環境,自己是一個 PropertyResolver,可是提供了 Profile 特性,便可以根據環境獲得相應數據(即激活不一樣的 Profile,能夠獲得不一樣的屬性數據,好比用於多環境場景的配置(正式機、測試機、開發機 DataSource 配置)Profile
:剖面,只有激活的剖面的組件/配置纔會註冊到 Spring 容器,相似於 maven 中 profile也就是說,新的 API 主要從配置屬性、解析屬性、不一樣環境解析不一樣的屬性、激活哪些組件/配置進行註冊這幾個方面進行了從新設計,使得 API 的目的更加清晰,並且功能更增強大。spring
@Test public void test() { Environment env = new StandardEnvironment(); // 1. 操做系統的環境變量 Map<String, Object> systemEnvironment = ((StandardEnvironment) env).getSystemEnvironment(); Assert.assertNotNull(systemEnvironment); // 2. JVM 屬性配置 Map<String, Object> systemProperties = ((StandardEnvironment) env).getSystemProperties(); Assert.assertNotNull(systemProperties); // 3. 屬性 Assert.assertEquals("UTF-8", env.getProperty("file.encoding")); Assert.assertTrue(env.containsProperty("file.encoding")); // 4. 剖面 spring.profiles.default(默認爲 default) spring.profiles.active // 只要有一個返回 true acceptsProfiles 方法就返回 true,!a 爲不包含該 profiles Assert.assertTrue(env.acceptsProfiles("default")); Assert.assertTrue(env.acceptsProfiles("a", "default")); Assert.assertFalse(env.acceptsProfiles("a")); Assert.assertTrue(env.acceptsProfiles("!a", "b")); }
public abstract class PropertySource<T> { // 給數據源起個名稱 protected final String name; // 數據源,可能爲 Map 或 Properties ... protected final T source; public boolean containsProperty(String name) { return (getProperty(name) != null); } public abstract Object getProperty(String name); }
PropertySource 很是相似於 Map,數據源可來自 Map、Properties、Resource 等。PropertySource 接口有兩個特殊的子類:StubPropertySource 用於佔位用,ComparisonPropertySource 用於集合排序,不容許獲取屬性值。數據庫
MapPropertySource 的屬性來自於一個 Map,而 ResourcePropertySource 的屬性來自於一個 properties 文件,另外還有如 PropertiesPropertySource,其屬性來自 Properties,ServletContextPropertySource 的屬性來自 ServletContext 上下文初始化參數等等,你們能夠查找 PropertySource 的繼承層次查找相應實現。api
@Test public void PropertySourceTest() throws IOException { PropertySource mapPropertySource = new MapPropertySource("map", Collections.singletonMap("key", "source1")); Assert.assertEquals("value1", mapPropertySource.getProperty("key")); ResourcePropertySource resourcePropertySource = new ResourcePropertySource( "resource", "classpath:resources.properties"); Assert.assertEquals("value2", resourcePropertySource.getProperty("key")); }
CompositePropertySource 提供了組合 PropertySource 的功能,查找順序就是註冊順序。spring-mvc
@Test public void CompositePropertySourceTest() throws IOException { PropertySource propertySource1 = new MapPropertySource("source1", Collections.singletonMap("key", "value1")); PropertySource propertySource2 = new MapPropertySource("source2", Collections.singletonMap("key", "value2")); CompositePropertySource compositePropertySource = new CompositePropertySource("composite"); compositePropertySource.addPropertySource(propertySource1); compositePropertySource.addPropertySource(propertySource2); Assert.assertEquals("value1", compositePropertySource.getProperty("key")); }
另外還有一個 PropertySources,從名字能夠看出其包含多個 PropertySource。默認提供了一個 MutablePropertySources 實現,能夠調用 addFirst 添加到列表的開頭,addLast 添加到末尾,另外能夠經過 addBefore(propertySourceName, propertySource) 或 addAfter(propertySourceName, propertySource) 添加到某個 propertySource 前面/後面;最後你們能夠經過 iterator 迭代它,而後按照順序獲取屬性。mvc
注意:PropertySource 的順序很是重要,由於 Spring 只要讀到屬性值就返回。app
@Test public void PropertySourcesTest() throws IOException { PropertySource propertySource1 = new MapPropertySource("source1", Collections.singletonMap("key", "value1")); PropertySource propertySource2 = new MapPropertySource("source2", Collections.singletonMap("key", "value2")); MutablePropertySources propertySources = new MutablePropertySources(); propertySources.addFirst(propertySource1); propertySources.addLast(propertySource2); Assert.assertEquals("value1", propertySources.get("source1").getProperty("key")); Assert.assertEquals("value2", propertySources.get("source2").getProperty("key")); }
到目前咱們已經有屬性了,接下來須要更好的 API 來解析屬性了。框架
PropertyResolver 的使用參考:http://www.javashuo.com/article/p-pgbhqkkt-bs.html
Environment 是對 JDK 環境、Servlet 環境、Spring 環境的抽象;每一個環境都有本身的配置數據,如 System.getProperties()、System.getenv() 等能夠拿到 JDK 環境數據;ServletContext.getInitParameter()能夠拿到 Servlet 環境配置數據等等;也就是說 Spring 抽象了一個 Environment 來表示環境配置。
public interface Environment extends PropertyResolver { String[] getActiveProfiles(); String[] getDefaultProfiles(); // @since 5.1 廢棄,改用 Profiles(Profiles.of("dev")) @Deprecated boolean acceptsProfiles(String... profiles); boolean acceptsProfiles(Profiles profiles); }
從 API 上能夠看出,除了能夠解析相應的屬性信息外,還提供了剖面相關的 API。目的是:能夠根據剖面有選擇的進行註冊組件/配置。好比對於不一樣的環境註冊不一樣的組件/配置(正式機、測試機、開發機等的數據源配置)。它的主要幾個實現以下所示:
MockEnvironment
:模擬的環境,用於測試時使用;StandardEnvironment
:標準環境,普通 Java 應用時使用,會自動註冊 System.getProperties() 和 System.getenv()到環境;StandardServletEnvironment
:標準 Servlet 環境,其繼承了 StandardEnvironment,Web 應用時使用,除了 StandardEnvironment 外,會自動註冊 ServletConfig(DispatcherServlet)、ServletContext 及 JNDI 實例到環境;<context-param> <param-name>myConfig</param-name> <param-value>hello</param-value> </context-param> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> </servlet>
使用 StandardServletEnvironment 加載時,默認除了 StandardEnvironment 的兩個屬性外,還有另外三個屬性:servletContextInitParams(ServletContext)、servletConfigInitParams(ServletConfig)、jndiProperties(JNDI)。
(1) 註解
@Autowired Environment env;
(2) ApplicationContext
applicationContext.getEnvironment();
profile 剖面,大致意思是:咱們程序可能從某幾個剖面來執行應用,好比正式機環境、測試機環境、開發機環境等,每一個剖面的配置可能不同(好比開發機可能使用本地的數據庫測試,正式機使用正式機的數據庫測試)等;所以呢,就須要根據不一樣的環境選擇不一樣的配置;若是 maven 中的 profile 的概念。
profile 有兩種:
查找順序是:先進性明確激活的匹配,若是沒有指定明確激活的(即集合爲空)就找默認的;配置屬性值從 Environment 讀取。
profile 設置方式常見的有三種:
(1) -D 傳入系統參數
-Dspring.profiles.active=dev
(2) web 環境
<context-param> <param-name>spring.profiles.active</param-name> <param-value>dev</param-value> </context-param>
(3) xml 配置
經過在 beans 標籤上加上 profile 屬性,這樣當咱們激活相應的 profile 時,此 beans 標籤下的 bean 就會註冊,以下所示:
<beans> <beans profile="dev"> <bean id="dataSource" class="..."> </bean> </beans> <beans profile="test"> <bean id="dataSource" class="..."> </bean> </beans> </beans>
啓動應用時設置相應的 "spring.profiles.active" 便可。另外,若是想指定一個默認的,可使用
(4) 註解配置
Java Config 方式的 Profile,功能等價於 XML 中的
@Profile("dev") @Configuration @PropertySource(value = "classpath:resources.properties", ignoreResourceNotFound = false) public class AppConfig { @Bean public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } }
Spring4 提供了一個新的 @Conditional 註解,請參考 http://jinnianshilongnian.iteye.com/blog/1989379
(5) @ActiveProfiles()
在測試時,有時候不能經過系統啓動參數/上下文參數等指定 Profile,此時 Spring 測試框架提供了 @ActiveProfiles() 註解,示例以下:
@ActiveProfiles("test") @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = GenericConfig.class) public class GenricInjectTest { }
到此整個 Spring 的屬性管理 API 就介紹完了,對於屬性管理,核心是 Environment。
參考:
天天用心記錄一點點。內容也許不重要,但習慣很重要!