目录
一、简介
Profile的意思是配置,对于应用程序来说,不同的环境需要不同的配置。
比如:
- 开发环境,应用需要连接一个可供调试的数据库单机进程
- 生产环境,应用需要使用正式发布的数据库,通常是高可用的集群
- 测试环境,应用只需要使用内存式的模拟数据库
Spring框架提供了多profile的管理功能,我们可以使用profile功能来区分不同环境的配置。
二、 区分Bean对象
首先,我们先看看如何基于Profile来定义一个Bean。
通过@Profile注解可以为一个Bean赋予对应的profile名称,如下:
- @Component
- @Profile("dev")
- public class DevDatasourceConfig
上面的DevDatasourceConfig被定义为 profile=dev,于是该Bean只会在dev(开发环境)模式下被启用。
如果需要定义为非dev环境,可以使用这样的形式:
- @Component
- @Profile("!dev")
- public class DevDatasourceConfig
XML风格配置
上面的例子也可以使用XML配置文件达到同样的目的,如下:
- <beans profile="dev">
- <bean id="devDatasourceConfig"
- class="org.baeldung.profiles.DevDatasourceConfig" />
- </beans>
读取Profile
通过ConfigurableEnvironment这个Bean 可以获得当前的Profile,如下:
- public class ProfileManager {
- @Autowired
- Environment environment;
-
- public void getActiveProfiles() {
- for (final String profileName : environment.getActiveProfiles()) {
- System.out.println("Currently active profile - " + profileName);
- }
- }
- }
三、 设置Profile
接下来,为了让容器"仅仅注册那些所需要的Bean",我们需要通过一些手段来设置当前的profile。
有很多方法可以达到这个目的,下面一一介绍。
3.1 WebApplicationInitializer接口
在Web应用程序中,通过WebApplicationInitializer可以对当前的ServletContext进行配置。
如下,通过注入spring.profiles.active变量可以为Spring上下文指定当前的 profile:
- @Configuration
- public class MyWebApplicationInitializer
- implements WebApplicationInitializer {
-
- @Override
- public void onStartup(ServletContext servletContext) throws ServletException {
-
- servletContext.setInitParameter(
- "spring.profiles.active", "dev");
- }
- }
3.2 通过 web.xml定义
与上面的方法类似,在web.xml中通过context-param元素也可以设置profile。
但前提是当前应用程序使用了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>
3.3 JVM启动参数
通过Java程序启动参数同样可以对profile进行设定,如下:
java -jar application.jar -Dspring.profiles.active=dev
spring-boot-maven-plugin插件也支持设定profile,其原理也是通过启动参数实现,可以参考这里
https://docs.spring.io/spring-boot/docs/current/maven-plugin/examples/run-profiles.html
3.4 环境变量
在Unix/Linux环境中,可以通过环境变量注入profile的值:
- export spring_profiles_active=dev
- java -jar application.jar
3.5 application.properties
可以在application.properties配置文件中指定spring.profiles.active属性:
spring.profiles.active=dev
SpringBoot默认会加载并读取该配置,当发现为profile=dev时,会同时关联加载application-dev.properties这个配置。
这种方式非常简单,可以实现对不同环境采用单独的配置文件进行隔离。
3.6 Maven Profile
Maven本身也提供了Profile的功能,可以通过Maven的Profile配置来指定Spring的Profile。
这种做法稍微有点复杂,需要先在pom.xml中设定不同的 maven profile,如下:
- <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>
这里,分别声明了dev和prod两个profile,每个profile都包含了一个spring.profiles.active属性,这个属性用来注入到 Spring中的profile入参。
在SpringBoot的配置文件application.properties中,需要替换为这个maven传入的property:
- ## 使用Maven的属性进行替换
- spring.profiles.active=@spring.profiles.active@
接下来,需要让Maven在打包时能将application.properties进行过滤处理,同时替换掉变量,需编辑pom.xml如下:
- <build>
- <resources>
- <resource>
- <directory>src/main/resources</directory>
- <filtering>true</filtering>
- </resource>
- </resources>
- </build>
这里定义了filtering=true,因此Resource打包插件会对配置文件执行过滤。
如果你的项目pom定义继承自 spring-boot-starter-parent,那么可以不需要配置这个filter
最后,在maven打包时指定参数如下:
mvn clean package -Pprod
3.7 使用 @ActiveProfiles
@ActiveProfile 是用于单元测试场景的注解,可以为测试代码指定一个隔离的profile,如下:
- @ActiveProfiles("test")
- public void ApiTest{
- ...
- }
3.8 使用 ConfigurableEnvironment
ConfigurableEnvironment 这个Bean封装了当前环境的配置信息,你可以在启动应用前进行设定操作:
- SpringApplication application = new SpringApplication(MyApplication.class);
-
- //设置environment中的profiler
- ConfigurableEnvironment environment = new StandardEnvironment();
- environment.setActiveProfiles("dev","join_dev");
-
- application.setEnvironment(environment);
- application.run(args)
3.9 SpringApplication.setAdditionalProfiles
SpringApplication这个类还提供了setAdditionalProfiles方法,用来让我们实现"附加"式的profile。
这些profile会同时被启用,而不是替换原来的active profile,如下:
- SpringApplication application = new SpringApplication(MyApplication.class);
- application.setAdditionalProfiles("new_dev");
这种方式可以实现无条件的启用profile,优先级是最高的。
当然,还可以通过设定spring.profiles.include来达到同样的目的。
四、 优先级
至此,我们已经提供了很多种方法来设定 Spring应用的profile,当它们同时存在时则会根据一定优先级来抉择,参考如下:
- SpringApplication.setAdditionalProfiles
- ConfigurableEnvironment、@ActiveProfiles
- Web.xml的 context-param
- WebApplicationInitializer
- JVM 启动参数
- 环境变量
- Maven profile、application.properties
从上至下,优先级从高到低排列。
其中,Maven profile与配置文件的方式相同,环境变量以及JVM启动参数会覆盖配置文件的内容。
1和2则属于进程内的控制逻辑,优先级更高。
如果在启动SpringBoot应用前对当前ConfigurableEnvironment对象注入了profile,则会优先使用这个参数, ActiveProfiles用于测试环境,其原理与此类似。
SpringApplication.setAdditionalProfiles则是无论如何都会附加的profile,优先级最高。
五、 案例
最后,我们在SpringBoot中演示一个使用Profile的例子。
一般,在开发环境和生产环境中的数据源配置是不同的,借助Profile我们可以定义出不同环境的数据源Bean。
首先我们先创建一个接口:
- public interface DatasourceConfig {
- public void setup();
- }
对于开发环境,DatasourceConfig实现如下:
- @Component
- @Profile("dev")
- public class DevDatasourceConfig implements DatasourceConfig {
- @Override
- public void setup() {
- System.out.println("Setting up datasource for DEV environment. ");
- }
- }
同样,为生产环境也实现一个DatasourceConfig:
- @Component
- @Profile("production")
- public class ProductionDatasourceConfig implements DatasourceConfig {
- @Override
- public void setup() {
- System.out.println("Setting up datasource for PRODUCTION environment. ");
- }
- }
接下来,我们声明一个Bean,对数据源执行初始化方法:
- @Component
- public class SpringProfilesTest {
- @Autowired
- DatasourceConfig datasourceConfig;
-
- @PostConstruct
- public void setupDatasource() {
- datasourceConfig.setup();
- }
- }
之后,在application.properties的配置为:
spring.profiles.active=dev
启动SpringBoot 应用,发现输出如下:
Setting up datasource for DEV environment.
此时说明dev的profile被启用了!
参考文档
https://www.baeldung.com/spring-profiles
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
http://dolszewski.com/spring/spring-boot-properties-per-maven-profile/
https://www.concretepage.com/spring-5/activeprofiles-example-spring-test
https://docs.spring.io/spring-boot/docs/current/maven-plugin/examples/run-profiles.html