标签:翻译
Spring
原文地址: https://www.baeldung.com/spring-profiles
更多Spring实战内容,请参考Spring - 实战指南
1. 概述
这篇文章将阐述怎么在Spring中使用Profile
从Spring 3.1开始,我们能够将bean映射到不同的profile上,如dev, test, prod等。
我们也能够根据环境(environment)来激活不同的profile,从而加载我们需要的bean。
2. 在Bean上使用@Profile
我们先从简单的例子开始,看看怎么把bean绑定到不同的profile上。
使用@Profile
注解,我们可以将bean绑定到指定的profile上。这个注解支持绑定一个或多个profile。
试想这样一个场景:我们有一个bean,只在开发环境需要,线上环境不需要。那么我们可以通过注解将这个bean绑定到dev profile
上。这样,这个bean只会存在于开发环境,而在其他环境中不会被加载。如下所示:
@Component
@Profile("dev")
public class DevDatasourceConfig
上面的写法是指绑定bean到dev profile
。如果想绑定bean到除dev
以外的profile呢。可以使用NOT操作符。如下所示:
@Component
@Profile("!dev")
public class DevDatasourceConfig
译者注:
@Profile
的声明如下:public @interface Profile { String[] value(); }
value
是个数组,支持多个值。绑定多个profile,如下所示:@Profile(value = {"dev", "test"})
3. 在XML中声明Profile
除了使用@Profile
注解,还可以在XML中绑定profile。
<bean>
标签有个profiles
属性。多个profile之间使用逗号分隔:
profile还是profiles???
<beans profile="dev">
<bean id="devDatasourceConfig"
class="org.baeldung.profiles.DevDatasourceConfig" />
</beans>
4. 设置profile
上面只是将bean和profile进行了绑定,下一步需要设置和激活profile,才能使不同的bean被注册到容器中。方法有很多种,下面是一些例子:
4.1 使用WebApplicationInitializer
interface
这是一种编程的方式(与之对应是配置方式)
在web应用中,WebApplicationInitializer
可以被用来配置ServletContext
。
译者注:
WebApplicationInitializer
在spring-web中
方法如下:
@Configuration
public class MyWebApplicationInitializer
implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter(
"spring.profiles.active", "dev");
}
}
译者注:
这种方式,直接把要绑定的profile硬编码到代码中,是非常不优雅,也不方便的。
4.2 使用ConfigurableEnvironment
你也可以直接在环境中设置profile:
@Autowired
private ConfigurableEnvironment env;
...
env.setActiveProfiles("someProfile");
译者注:
问题同4.1
4.3 在web.xml
中配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-config.xml</param-value>
</context-param>
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>dev</param-value>
</context-param>
译者注:
问题同4.1,4.2。 本人不赞成任何硬编码的方式
4.4 通过JVM参数设置
profile的名字还可以通过JVM参数的方式设置。在启动的时候,添加类似如下参数:
-Dspring.profiles.active=dev
译者注:
如java -jar xxx.jar -Dspring.profiles.active=dev
4.5 通过环境变量设置
通过设置环境变量,也是可以的:
export spring_profiles_active=dev
4.6 Maven Profile
Spring profile也可以结合maven profile使用,通过设置spring.profiles.active
属性:
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<spring.profiles.active>dev</spring.profiles.active>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<spring.profiles.active>prod</spring.profiles.active>
</properties>
</profile>
</profiles>
同时,还需要在application.properties
(如果使用spring boot的话)中添加如下设置:
spring.profiles.active=@spring.profiles.active@
另外,还需要再pom.xml
文件中添加如下配置:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
...
</build>
译者注:
在pom.xml
中添加的配置,意思是开启占位符替换。可参考:Maven Filtering
结合使用maven profile后,就可以在打包的时候激活某个profile:
mvn clean package -Pprod
译者注:
个人认为,结合maven profile的这种办法,灵活度最高,也最方便,推荐。
4.7 Test中使用@ActiveProfiles
在test时,如何指定profile呢?也很简单,通过@ActiveProfiles
注解就可以了。
@ActiveProfiles("dev")
5. 默认profile
如果不指定任何profile,那么这个bean就属于default
profile
当没有任何profile被激活时,spring也支持设置默认profile。就是通过spring.profiles.default
参数。
6. 获取被激活的profile
一旦profile被激活,我们就可以通过Environment
,在运行时获取这些profile的信息:
public class ProfileManager {
@Autowired
Environment environment;
public void getActiveProfiles() {
for (final String profileName : environment.getActiveProfiles()) {
System.out.println("Currently active profile - " + profileName);
}
}
}
7. 使用Profile的例子
理论总是抽象的,下面我们通过一些例子来深入理解。
试想这样一个场景:我们要分别针对开发环境和线上环境,对datasource进行设置。我们先创建一个DatasourceConfig
接口。这个接口需要在两个环境中都被实现。
public interface DatasourceConfig {
public void setup();
}
开发环境的实现:
@Component
@Profile("dev")
public class DevDatasourceConfig implements DatasourceConfig {
@Override
public void setup() {
System.out.println("Setting up datasource for DEV environment. ");
}
}
线上环境的实现:
@Component
@Profile("production")
public class ProductionDatasourceConfig implements DatasourceConfig {
@Override
public void setup() {
System.out.println("Setting up datasource for PRODUCTION environment. ");
}
}
下面我们写个单元测试,并注入DatasourceConfig
。那么我们通过设置不同的profile,就会分别注入DevDatasourceConfig
bean和ProductionDatasourceConfig
bean。
public class SpringProfilesTest {
@Autowired
DatasourceConfig datasourceConfig;
public void setupDatasource() {
datasourceConfig.setup();
}
}
当dev
profile被激活的时候,会有如下输出:
Setting up datasource for DEV environment.
8. 在Spring Boot中使用Profile
Spring Boot除了支持所有的profile配置,还有提供一些额外功能。
spring.profiles.active
的初始化可以在配置文件中设定:
spring.profiles.active=dev
当然也可以在程序中设定:
SpringApplication.setAdditionalProfiles("dev");
还可以在pom.xml文件中的spring-boot-maven-plugin
中配置:
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>dev</profile>
</profiles>
</configuration>
</plugin>
...
</plugins>
用maven启动,可执行命令:
mvn spring-boot:run
但是Spring Boot带来的最重要的特性是profile-specific profiles文件,这些文件的命名方式需要遵循applications-{profile}.properties
的格式。
举个例子:我们可以在开发环境和线上环境使用不同的数据库。如开发环境使用h2,线上环境使用mysql。那么,我们分别需要创建如下两个文件:
application-production.properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=root
spring.datasource.password=root
application-dev.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
如果激活的profile是dev
,则application-dev.properties配置文件会被自动加载。如果激活的profile是production
,则application-production.properties 配置文件会被加载。
通过这种方式,我们就很容易地针对不同环境,配置不同的配置文件。