Spring Environment(一)API 介紹

Spring Environment(一)API 使用

Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html

Spring 3.1 提供了新的屬性管理 API,並且功能很是強大且很完善,對於一些屬性配置信息都應該使用新的 API 來管理。位於 org.springframework.core.env 包內。java

Spring Environment 屬性配置管理系列文章:web

  1. Spring Environment(一)API 介紹
  2. Spring Environment(二)源碼分析
  3. Spring Environment(三)生命週期

1、新的屬性管理 API

  • PropertySource:屬性源,key-value 屬性對抽象,好比用於配置數據
  • PropertyResolver:屬性解析器,用於解析相應 key 的 value
  • Environment:環境,自己是一個 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"));
}

2、PropertySource

PropertySource 類圖

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 用於集合排序,不容許獲取屬性值。數據庫

2.1 PropertySource 實現類

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"));
}

2.2 CompositePropertySource

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"));
}

2.3 PropertySources

PropertySources 類圖

另外還有一個 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 來解析屬性了。框架

3、PropertyResolver

PropertyResolver 的使用參考:http://www.javashuo.com/article/p-pgbhqkkt-bs.html

4、Environment

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 實例到環境;

4.1 web.xml 配置 Servlet 屬性

<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)。

4.2 Environment 獲取

(1) 註解

@Autowired  
Environment env;

(2) ApplicationContext

applicationContext.getEnvironment();

5、Profile

profile 剖面,大致意思是:咱們程序可能從某幾個剖面來執行應用,好比正式機環境、測試機環境、開發機環境等,每一個剖面的配置可能不同(好比開發機可能使用本地的數據庫測試,正式機使用正式機的數據庫測試)等;所以呢,就須要根據不一樣的環境選擇不一樣的配置;若是 maven 中的 profile 的概念。

profile 有兩種:

  • 默認的:經過 "spring.profiles.default" 屬性獲取,若是沒有配置默認值是 "default"
  • 明確激活的:經過 "spring.profiles.active" 獲取

查找順序是:先進性明確激活的匹配,若是沒有指定明確激活的(即集合爲空)就找默認的;配置屬性值從 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" 便可。另外,若是想指定一個默認的,可使用 指定(若是不是 default,能夠經過 "spring.profiles.default" 指定)。

(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。

參考:

  1. 《pring3.1新屬性管理API:PropertySource、Environment、Profile》:https://jinnianshilongnian.iteye.com/blog/2000183

天天用心記錄一點點。內容也許不重要,但習慣很重要!

相關文章
相關標籤/搜索