1.13. Environment Abstraction
Environment接口:
public interface Environment extends PropertyResolver {
String[] getActiveProfiles();
String[] getDefaultProfiles();
/** @deprecated */
@Deprecated
boolean acceptsProfiles(String... var1);
boolean acceptsProfiles(Profiles var1);
}
负责profile和properties,profile表示某种环境下激活某部分bean,profile一般可以是product、test等,表示在不同环境下激活不同的配置;properties就是系统中常说的属性(系统属性、配置文件中的属性、jvm系统属性)。Environment接口负责这些工作。
1.13.1. Bean Definition Profiles
Using @Profile
@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");
}
}
通过自定义注解可以简化配置:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Profile("production")
public @interface Production {
}
profile支持表达式:
- !: A logical “not” of the profile
- &: A logical “and” of the profiles
- |: A logical “or” of the profiles
For example, given @Profile({"p1", "!p2"}), registration will occur if profile 'p1' is active or if profile 'p2' is not active.
@Profile用于方法:
@Configuration
public class AppConfig {
@Bean("dataSource")
@Profile("development")
public DataSource standaloneDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
@Bean("dataSource")
@Profile("production")
public DataSource jndiDataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
XML Bean Definition Profiles
xml配置方式,分开定义:
xml配置定义,集中定义:
The XML counterpart does not support the profile expressions described earlier. It is possible, however, to negate a profile by using the ! operator
Activating a Profile
前面讲述了如何定义profile,当定义完成后,还需要激活才能将这些配置注册到容器中。有以下几种激活方法。
- 直接在代码中使用setActiveProfiles方法激活
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();
- 通过传入spring.profiles.active参数激活,可以是环境变量,jvm参数等
支持同时激活多个profile:
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
通过spring.profiles.active:
-Dspring.profiles.active="profile1,profile2"
Default Profile
如果没有激活任何profile,支持设置缺省profile,默认使用缺省profile:
@Configuration
@Profile("default")
public class DefaultDataConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.build();
}
}
还可以通过如下方式设置缺省profile:
You can change the name of the default profile by using setDefaultProfiles() on the Environment or ,declaratively, by using the spring.profiles.default property.
1.13.2. PropertySource Abstraction
Environment提供了现成的实现帮助我们直接获取相应的配置属性:
ApplicationContext ctx = new GenericApplicationContext();
Environment env = ctx.getEnvironment();
boolean containsMyProperty = env.containsProperty("my-property");
System.out.println("Does my environment contain the 'my-property' property? " + containsMyProperty);
默认实现为StandardEnvironment,它优先查找jvm环境系统属性(-D传入,System.getProperties()),其次再考虑环境变量(System.getenv())。
Spring支持自定义PropertySources,MyPropertySource 拥有最高优先级:
ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());
1.13.3. Using @PropertySource
@PropertySource注解支持添加PropertySource,指定配置文件路径即可,必须为key=value方式配置:
@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;
}
}
支持占位符,占位符的替换字符串值由其他已经加载的配置属性决定:
@Configuration
@PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")
public class AppConfig {
@Autowired
Environment env;
@Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
针对上述代码的说明:
Assuming that my.placeholder is present in one of the property sources already registered (for example, system properties or environment variables), the placeholder is resolved to the corresponding value. If not, then default/path is used as a default. If no default is specified and a property cannot be resolved, an IllegalArgumentException is thrown.
1.13.4. Placeholder Resolution in Statements
只要占位符的key值在Environment存在,占位符就可以被成功替换:
1.14. Registering a LoadTimeWeaver
@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
}
所有容器中的类都会默认实现LoadTimeWeaverAware接口:
Once configured for the ApplicationContext, any bean within that ApplicationContext may implement LoadTimeWeaverAware, thereby receiving a reference to the load-time weaver instance.
字面意思是加载时织入,具体意义等到后续章节会有介绍。