Environment是一个集成到容器中的特殊抽象,它针对应用环境建立了profile和properties。
profile:包含了多个bean定义的一个逻辑集合,只有当指定的profile倍激活时,其中的bean才会被激活。通过XML定义或通过注解,bean都可以配置到profile中。Environment与profile相关联,然后决定来激活哪个profile或哪个为默认的profile。
properties:它在应用中有着重要作用,如property文件、JVM系统的property、系统环境变量、JNDI、srevlet上下文参数、Map等。Environment与property相关联,给开发者一个方便的服务接口来配置这些数据源,并正确解析。
1、bean定义的profile
在容器中bean定义的profile是一种允许不同环境注册不同的bean的机制,适用以下场景:
1)解决内存中数据源问题,可以在不同环境中访问不同的数据源,如dev、sit、pre、prd环境等。
2)仅在开发环境中使用一些监视服务。
3)在不同环境中使用不同的bean实现。
如果泛化了一些特殊环境下引用的bean定义,可以将其中指定的bean注入特定的上下文中,而不是注入所有的上下文中。
2、@Profile
@Profile注解允许开发者表示一个组件是否适合在当前环境下进行注册,只有当前的profile被激活时,对应的bean才会被注册到上下文中。
@Configuration
@Profile("dev")
public class DataConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/config/sql/schema.sql")
.addScript("classpath:com/config/sql/test-data.sql").build();
}
}
@Configuration
@Profile("prd")
public class JndiDataConfig {
@Bean
public DataSource dataSource() throws Exception {
Context ctx =new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
@Profile注解可以作为元注解来使用,如下自定义的@Prd注解可以替代@Profile("prd"):
@Profile注解也可以在方法级别使用,还可以声明在包含@Bean注解的方法上。如下:
@Configuration
public class AppConfig {
@Bean
@Profile("dev")
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/config/sql/schema.sql")
.addScript("classpath:com/config/sql/test-data.sql").build();
}
@Bean
@Profile("prd")
public DataSource dataSource() throws Exception {
Context ctx =new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
如果配置了@Configuration的类同时也配置了@profile,则所有配置了@Bean注解的方法和@Import注解的类都会被传递为该profile。除非这个profile被激活,否则其中的bean定义都不会被激活。如果配置为@Component或@Configuration的类标记了@profile({"p1","p2"}),那么这个类当且仅当profile为p1或p2时才会被激活。如果某个profile的前缀为“!”,则@profile注解的类只有在当前的profile没被激活时才能生效。如配置为@profile({"p1","!p2"})则注册的行为会在profile为p1或profile为非p2时被激活。
3、XML中定义的profile
在XML中配置<beans/>的profile属性。
<beans profile="dev"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="...">
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:com/config/sql/schema.sql">
<jdbc:script location="classpath:com/config/sql/test-data.sql">
</jdbc:embedded-database>
</beans>
<beans profile="prd"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="...">
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource" />
</beans>
或者通过嵌套<beans>标签来定义:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="...">
<beans profile="dev">
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:com/config/sql/schema.sql">
<jdbc:script location="classpath:com/config/sql/test-data.sql">
</jdbc:embedded-database>
</beans>
<beans profile="prd">
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource" />
</beans>
</beans>
4、激活profile
有多种方法来激活一个profile,最直接的方式是通过编程的方式来直接调用Environment API。ApplicationContext中包含以下接口:
AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev");
context.register(SomeConfig.class,DataConfig.class,PrdDataConfig.class);
context.refresh();
profile还可以通过spring.profiles.active中的属性来指定,可以通过系统环境变量、JVM系统变量、servlet上下文中的参数或JNDI的一个参数来写入。profile的定义并非是互斥关系,开发者可以在同一时间激活多个profile。
context.getEnvironment().setActiveProfiles("dev","sit");
也可以通过spring.profiles.active来指定逗号分隔的多个profile名称。
-Dspring.profiles.active=“profile1,profile2”
5、默认profile
@Configuration
@Profile("default")
public class DataConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/config/sql/schema.sql")
.addScript("classpath:com/config/sql/test-data.sql").build();
}
}
如果没有其他profile被激活,则以上定义的dataSource将被创建,这种方式是默认情况下提供bean定义的一种方式。一旦任何一个profile被激活,默认的profile将不会被激活。默认的profile的名称可以通过Environment中的setActiveProfiles()或通过spring.profiles.default属性来更改。
6、@PropertySource
@PropertySource注解提供了一种方便的机制将PropertySource添加到spring的Environment中。给定一个文件app.properties包含了key-value对testbean.name=myTestBean,以下代码使用@PropertySource调用testbean.setName()将返回myTestBean。
@Configuration
@PropertySource("classpath:/com/xlws/app.properties")
public class AppConfig {
@Autowired
Environment env;
@Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
任何@PropertySource注解中如${...}的占位符,都可以被解析为Environment中的属性资源。如下:
@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;
}
}
假设my.placeholder是已经注册到Environment中的资源,若有JVM系统属性或环境变量,占位符会解析成对象的值,若没有则default/path会作为默认值。如果没有指定默认值,并且占位符也解析不出来,将会抛出异常IllegalArgumentException。
7、占位符解析
开发者可以任意配置占位符:
1)可以自由调整系统变量和环境变量的优先级。
2)可以额外增加自己的属性源信息。
以下XML配置不关心customer属性在哪里定义,只要这个值在Environment中有效即可:
<beans>
<import resource="com/xlws/service/${customer}-config.xml" />
</beans>
--参考文献《Srping5开发大全》
网友评论