通过为beans设置不同的profile,实现不同的环境运行不同的配置。我们的产品分为开发环境development,测试环境qa,以及生产环节production,我们为bean归属不同的profile,在不同的环境使用,例如数据库的ip地址等。
自动扫描的小例子
我们仍使用欢迎词的小例子,采用自动扫描的方式,欢迎词接口有两个不同的实现,分别用在不同的环境。
第一个实现,用于开发环境和测试环境
@Service
@Profile({"development","qa"})
public class GreetingServiceImpl implements GreetingService{
@Override
public String getGreeting(String name) {
return "Hello," + name + "!";
}
}
第二个实现,用于生产环节
@Service
@Profile("production")
public class GreetingServiceImpl2 implements GreetingService{
@Override
public String getGreeting(String name) {
return "Hello, dear " + name + "!";
}
}
GreetingService实例的加载本例在root上下文,因此我们将其作为上下文属性设置,在web.xml中:
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>qa</param-value>
</context-param>
如果是Servlet相关,则设置在servlet中,如下:
<servlet>
...
<init-param>
<param-name>spring.profiles.active</param-name>
<param-value>development</param-value>
</init-param>
...
</servlet>
配置文件例子
在xml中设置
profile可以用在@Componment中,例子如下:<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" ...>
<beans profile="development,qa">
<jdbc:embedded-database id="dataSource" type="HSQL">
<jdbc:script location="classpath:com/wrox/config/sql/schema.sql"/>
<jdbc:script location="classpath:com/wrox/config/sql/test-data.sql"/>
</jdbc:embedded-database>
</beans>
<beans profile="production">
<context:property-placeholder location="file:/settings.properties" />
<jee:jndi-lookup id="dataSource" jndi-name="java:/comp/env/${production.dsn}" />
</beans>
...
</beans>
在代码中设置
配置接口
interface DataConfiguration{
DataSource dataSource();
}
配置1 :"development", "qa"
@Configuration
@Profile({"development", "qa"})
public class DevQaDataConfiguration implements DataConfiguration{
@Override
@Bean
public DataSource dataSource(){
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/wrox/config/sql/schema.sql")
.addScript("classpath:com/wrox/config/sql/test-data.sql")
.build();
}
}
配置2 :"production"
@Configuration
@Profile("production")
@PropertySource("file:settings.properties")
public class ProductionDataConfiguration implements DataConfiguration{
@Value("production.dsn")
String dataSourceName;
@Override
@Bean
public DataSource dataSource(){
return new JndiDataSourceLookup()
.getDataSource("java:/comp/env/" + this.dataSourceName);
}
}
根上下文配置
@Configuration
@Import({DevQaDataConfiguration.class, ProductionDataConfiguration.class})
@ComponentScan(
basePackages = "com.wrox.site",
excludeFilters = @ComponentScan.Filter(Controller.class)
)
public class RootContextConfiguration{
}
web.xml
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>development</param-value>
</context-param>
如果有多个profile,可以在中间加上逗号,例如
<param-value>profile1,profile2</param-value>
运行参数:-Dspring.profiles.active
我们可以在运行命令行中加入 -Dspring.profiles.active=development
如果多个profile,中间加上逗号即可。
在代码中设置profile
对于application context,如下:configurableEnvironment.setActiveProfiles("development");
configurableEnvironment.setActiveProfiles("profile1", "profile2");
但是既然我们在代码中强制设定,profile的使用就失去了初衷:改个配置就换个环境。
自定义标记
@Profile和@Component一样,可以作为原标记(meta-annotation),即可以创建自己的标记作为@Profile标记来使用。@Documented
@Retention(value=RetentionPolicy.RUNTIME)
@Target(value={ElementType.TYPE, ElementType.METHOD})
@Profile("development")
public @interface Development{}
自定义的@Development标记等同与@Profile("development")。
其他
- 是否有其他替代方式,例如使用property文件来设定,使用profile可能会令代码变得复杂,是否值得?
- 一般而言,QA环境更为接近生产环节,而和开发环境差异较大
- 一般而言,不要使用profile来进行安全或者许可,因为用户可以JVM命令重新设置profile来绕开安全检查和许可限制。