Environment
環境在容器中是一個抽象的集合,是指應用環境的2個方面: profiles和 properties.
profile
配置是一個被命名的,bean定義的邏輯組,這些bean只有在給定的profile配置激活時才會注冊到容器。不管是XML還是注解,Beans都有可能指派給profile配置。Environment環境對象的作用,對於profiles配置來說,它能決定當前激活的是哪個profile配置,和哪個profile是默認。
在所有的應用中,Properties屬性扮演一個非常重要的角色,可能來源於一下源碼變量:properties文件,JVM properties,system環境變量,JNDI, servlet context parameters上下文參數,專門的Properties對象,Maps等等。Environment對象的作用,對於properties來說,是提供給用戶方便的服務接口,方便撰寫配置、方便解析配置。
bean定義profiles是核心容器內的一種機制,該機制能在不同環境中注冊不同的bean。環境的意思是,為不同的用戶做不同的事兒,該功能在很多場景中都非常有用,包括:開發期使用內存數據源,在QA或者產品上則使用來自JNDI的相同的數據源開發期使用監控組件,當部署以后則關閉監控組件,是應用更高效為用戶各自注冊自定義bean實現.
考慮一個實際應用中的場景,現在需要一個DataSource。開測試環境中,這樣配置:
@Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) .addScript("my-schema.sql") .addScript("my-test-data.sql") .build(); }
現在想一想,如何將應用部署到QA或者生產環境,假設生產環境中使用的JNDI。我們的dataSource bean看起來像這樣:
@Bean(destroyMethod="") public DataSource dataSource() throws Exception { Context ctx = new InitialContext(); return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); }
我們需要在某些上下文環境中使用某些bean,在其他環境中則不用這些bean。你也許會說,你需要在場景A中注冊一組bean定義,在場景B中注冊另外一組。先看看我們如何修改配置來完成此需求。
@Profile注解的作用,是在一個或者多個指定profiles激活的情況下,注冊某個組件。使用上面的樣例,重寫dataSource配置:
@Configuration @Profile("dev") public class StandaloneDataConfig { @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) .addScript("classpath:com/bank/config/sql/schema.sql") .addScript("classpath:com/bank/config/sql/test-data.sql") .build(); } } @Configuration @Profile("production") public class JndiDataConfig { @Bean(destroyMethod="") public DataSource dataSource() throws Exception { Context ctx = new InitialContext(); return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); } }
開啟profile
要修改配置,我們仍然需要指定要激活哪個文件。如果現在運行上面的樣例應用,它會拋異常NoSuchBeanDefinitionException,因為容器找不到dataSourcebean。
有多種方式激活配置,但是最直接的方式是編程式的方式使用ApplicationContext API
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.getEnvironment().setActiveProfiles("dev"); ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class); ctx.refresh();
此外,還可以使用spring.profiles.active激活配置,該屬性可以配置在系統環境變量、JVM系統屬性、web.xml
中JNDI中的servlet context上下文參數
注意配置文件不是單選;可能會同時激活多個配置文件,編程式的使用方法setActiveProfiles(),該方法接收String數組參數,也就是多個配置文件名
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
//聲明式的使用spring.profiles.active ,值可以為逗號分隔的配置文件名列表, -Dspring.profiles.active="profile1,profile2"
如果沒有任何profile配置被激活,默認的profile將會激活。
默認profile配置文件可以更改,通過環境變量的setDefaultProfiles方法,或者是聲明的spring.profiles.default屬性值
Spring的環境抽象提供了用於檢索一系列的property sources屬性配置文件。
ApplicationContext ctx = new GenericApplicationContext(); Environment env = ctx.getEnvironment(); boolean containsFoo = env.containsProperty("foo"); System.out.println("Does my environment contain the ''foo'' property? " + containsFoo);
在上面的片段中,通過較高層次方式檢索SPring是否在當前環境中定義了foo property屬性。為了檢索該屬性,環境對象在一組PropertySource對象中執行檢索。PropertySource是key-value鍵值對配置文件的抽象,Spring的StandardEnvironment
配置了2個PropertySource對象.其一是JVM系統properties(System.getProperties()),另一個是一組系統環境變量System.getEnv()。
@PropertySource注解提供了一個方便的方式,用於增加一個PropertySource到Spring的環境中: 給定一個文件"app.properties"包含了key/value鍵值對testbean.name=myTestBean,下面的@Configuration類使用了@PropertySource
,使用這種方式調用testBean.getName()將會返回myTestBean。
@Configuration @PropertySource("classpath:/com/myco/app.properties") public class AppConfig { @Autowired Environment env; @Bean public TestBean testBean() { TestBean testBean = new TestBean(); testBean.setName(env.getProperty("testbean.name")); return testBean; } }
轉自:https://www.jianshu.com/p/49e950b0b008