Environment是集成在容器中的抽象接口,它对应用程序环境的两个关键方面进行建模:配置文件(profiles)和属性(properties)。
配置文件(profiles)
配置文件为核心容器中提供了一种机制,允许在不同的环境中注册不同的bean。这个“环境”对不同的用户可能意味着不同的东西,这个特性可以帮助处理很多用例,包括:
1、开发环境、测试环境和生产环境使用的数据源是不同的,通过配置文件管理对应数据源配置。
2、只有在将应用程序部署到性能环境时才注册监控基础设施。
3、为A客户和B客户的部署注册自定义的bean实现。
Environment 的作用是确定当前处于活动状态配置文件,以及默认情况下应该处于活动状态配置文件。
以开发环境和测试环境加载数据源为例,两个数据源实现:
//数据源1-内存数据库
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("my-schema.sql")
.addScript("my-test-data.sql")
.build();
}
//数据源1-jdbc访问数据库
@Bean(destroyMethod = "")
public DataSource dataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
如何根据当前环境在这两种数据源之间进行切换。Spring用户设计了一些方法来完成这项工作,通常依赖于系统环境变量(如启动参数 -Dspring.profiles.active=development)和XML配置的组合。配置文件是提供此问题解决方案的核心容器功能。
@Profile注解模式
@Configuration
@Profile("development")
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");
}
}
xml配置
用两个bean配置文件(适合配置bean多):
//development模式文件
<beans profile="development"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="...">
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
<jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
</jdbc:embedded-database>
</beans>
//production模式文件
<beans profile="production"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="...">
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>
用一个配置文件(适合配置bean少):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="...">
<!-- other bean definitions -->
<beans profile="development">
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
<jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
</jdbc:embedded-database>
</beans>
<beans profile="production">
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>
</beans>
激活配置文件
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
//用Environment激活配置文件,"development"可通过命令行参数传递进来
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();
属性(properties)
属性就是应用常用到的可配置参数,并且可能来自各种来源:属性文件、JVM系统属性(如*.properties、*.yml)、系统环境变量、JNDI、servlet上下文参数、特定属性对象、映射等等。Environment 的作用就是为用户提供方便的服务接口,用于从属性源中解析出相关属性。
spring框架和应用访问属性都是通过Environment提供的PropertySource对象中进行搜索。PropertySource是对任意键值对来源的简单抽象,而Spring的StandardEnvironment被配置了两个PropertySource对象——一个表示JVM系统属性集(System.getProperties()),另一个表示系统环境变量集(System.getenv())。
spring实现访问属性的设计比较复杂,类关系图大致如下:
从类关系图看出,基本是通过ProperyResolver(将属性资源解析成PropertySource供访问,注:属性文件的加载是在ResourceLoader中完成的)完成。这么设计的目的,需要阅读相关代码去体会。
属性文件默认支持:properties格式和yaml格式,如果是其它格式文件,需提供相应的解析器。
加载
自动加载
自动加载系统环境变量。
如果配置文件参数和系统环境变量参数重名,系统环境的优先级更高。
xml加载
单个加载
//方式1
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
property name="location" value="classpath:app.properties"/>
</bean>
//方式2
<context:property-placeholder location="classpath:app.properties"/>
多个文件加载:
方式1:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:app.properties</value>
<value>classpath*:app1.properties</value>
</list>
</property>
</bean>
方式2:
<context:property-placeholder location="app.properties,app1.properties"/>
注多个文件加载,有同名参数,后加载的覆盖前加载的。
如果是yaml格式文件,按如下配置:
<bean id="yamlProperties" class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">
<property name="resources" value="classpath:app.yml"/>
</bean>
<context:property-placeholder properties-ref="yamlProperties"/>
注解加载
@PropertySource(value={"classpath:app.properties","classpath:app1.properties"})
使用
@Value
这是应用使用配置参数最常用最简单的方法。
@Value("${JAVA_HOME}")