1. 概述
本篇文章将深入介绍 Spring 中的 Profiles 功能。
Profiles 是 Spring 框架的核心特性之一,它允许我们将 Bean 映射到不同的运行环境,例如开发环境(dev)、测试环境(test)和生产环境(prod)。
通过激活不同的 Profile,我们可以在不同环境中只加载所需的 Bean,从而实现配置的灵活切换。
2. 使用 @Profile
注解标记 Bean
最基础的做法是使用 @Profile
注解来指定某个 Bean 属于哪个 Profile。这个注解可以接受一个或多个 Profile 名称。
举个例子:我们有一个 Bean 只在开发环境使用,生产环境不需要部署它。
这时我们可以给这个 Bean 加上 @Profile("dev")
注解,这样它就只会在开发环境被注册进容器中:
@Component
@Profile("dev")
public class DevDatasourceConfig
⚠️ 小技巧:Profile 名称也可以加上 !
前缀表示“非”,例如 !dev
表示“除了 dev 以外的所有环境”。
如下代码所示,该组件只有在 dev
Profile 未激活时才会生效:
@Component
@Profile("!dev")
public class DevDatasourceConfig
3. 在 XML 中声明 Profile
除了注解方式外,Profile 也可以在 XML 配置文件中定义。<beans>
标签支持 profile
属性,用于指定该配置块适用的 Profile:
<beans profile="dev">
<bean id="devDatasourceConfig"
class="org.baeldung.profiles.DevDatasourceConfig" />
</beans>
4. 设置激活的 Profile
有了 Profile 的定义后,下一步就是告诉 Spring 当前应该激活哪个 Profile,以便注册对应的 Bean。
有多种方式可以设置激活的 Profile,下面我们逐一介绍。
4.1. 通过 WebApplicationInitializer
编程设置
在 Web 应用中,可以通过实现 WebApplicationInitializer
接口,在初始化 ServletContext
时设置激活的 Profile:
@Configuration
public class MyWebApplicationInitializer
implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter(
"spring.profiles.active", "dev");
}
}
4.2. 通过 ConfigurableEnvironment
编程设置
我们也可以直接通过注入的 ConfigurableEnvironment
来设置:
@Autowired
private ConfigurableEnvironment env;
...
env.setActiveProfiles("someProfile");
4.3. 在 web.xml
中通过上下文参数设置
在传统的 Web 应用中,可以在 web.xml
中通过上下文参数来设置激活的 Profile:
<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.4. 通过 JVM 系统参数设置
在启动应用时,可以通过 JVM 参数传递 Profile 名称:
-Dspring.profiles.active=dev
4.5. 通过环境变量设置
在 Unix 环境中,可以通过环境变量来激活 Profile:
export spring_profiles_active=dev
4.6. 通过 Maven Profile 设置
Spring Profile 也可以通过 Maven 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.profiles.active=@spring.profiles.active@
接下来需要在 pom.xml
中开启资源过滤:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
...
</build>
最后通过 Maven 命令指定 Profile 打包:
mvn clean package -Pprod
这会将应用打包为生产环境配置,并自动激活 prod
Profile。
4.7. 在测试中使用 @ActiveProfiles
在测试中,可以使用 @ActiveProfiles
注解来指定激活的 Profile:
@ActiveProfiles("dev")
4.8. Profile 激活优先级
当多个地方都设置了 Profile 时,它们的优先级如下(从高到低):
web.xml
中的上下文参数WebApplicationInitializer
- JVM 系统参数
- 环境变量
- Maven Profile
5. 默认 Profile
所有没有指定 Profile 的 Bean 都属于 default
Profile。
我们可以通过 spring.profiles.default
属性来设置默认 Profile,当没有其他 Profile 被激活时,这些 Bean 会自动生效。
6. 获取当前激活的 Profile
有时候我们需要在代码中动态获取当前激活的 Profile,Spring 提供了两种方式。
6.1. 使用 Environment
获取
注入 Environment
后,可以通过 getActiveProfiles()
方法获取:
public class ProfileManager {
@Autowired
private Environment environment;
public void getActiveProfiles() {
for (String profileName : environment.getActiveProfiles()) {
System.out.println("Currently active profile - " + profileName);
}
}
}
6.2. 使用 @Value
注入属性
也可以通过注入 spring.profiles.active
属性来获取:
@Value("${spring.profiles.active}")
private String activeProfile;
⚠️ 注意:如果没有激活的 Profile,会导致占位符注入失败,抛出 IllegalArgumentException
。
为避免这个问题,可以设置默认值:
@Value("${spring.profiles.active:}")
private String activeProfile;
如果需要获取多个 Profile,可以使用字符串分割:
public class ProfileManager {
@Value("${spring.profiles.active:}")
private String activeProfiles;
public String getActiveProfiles() {
for (String profileName : activeProfiles.split(",")) {
System.out.println("Currently active profile - " + profileName);
}
}
}
7. 示例:使用 Profile 区分数据源配置
下面通过一个实际例子来看如何使用 Profile。
假设我们需要为开发和生产环境分别配置不同的数据源。
首先定义一个通用接口:
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. ");
}
}
在测试中注入接口,Spring 会根据激活的 Profile 自动注入对应的实现类:
public class SpringProfilesWithMavenPropertiesIntegrationTest {
@Autowired
DatasourceConfig datasourceConfig;
public void setupDatasource() {
datasourceConfig.setup();
}
}
如果当前激活的是 dev
Profile,输出如下:
Setting up datasource for DEV environment.
8. Spring Boot 中的 Profile
Spring Boot 支持前面介绍的所有 Profile 配置方式,并且还提供了额外的功能。
8.1. 激活 Profile
在 Spring Boot 中,可以通过 application.properties
文件设置激活的 Profile:
spring.profiles.active=dev
⚠️ 从 Spring Boot 2.4 开始,该属性不能与 spring.config.activate.on-profile
同时使用,否则会抛出 ConfigDataException
。
我们也可以通过编程方式设置:
SpringApplication.setAdditionalProfiles("dev");
在 Maven 中,也可以通过 spring-boot-maven-plugin
插件指定 Profile:
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>dev</profile>
</profiles>
</configuration>
</plugin>
...
</plugins>
执行以下命令启动应用:
mvn spring-boot:run
8.2. Profile 特定的配置文件
Spring Boot 最强大的功能之一就是支持 Profile 特定的配置文件,文件名格式为:application-{profile}.properties
。
Spring Boot 会自动加载通用配置文件 application.properties
和特定 Profile 的配置文件。
例如,为 dev
和 production
分别配置不同的数据源:
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
✅ 这样就能轻松实现不同环境的配置隔离。
⚠️ 从 Spring Boot 2.4 开始,Profile 特定的配置文件不能再激活其他 Profile,否则会抛出异常。
8.3. 多文档配置文件
从 Spring Boot 2.4 开始,支持在单个 .properties
文件中使用 ---
分隔符定义多个 Profile 的配置:
my.prop=used-always-in-all-profiles
#---
spring.config.activate.on-profile=dev
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
#---
spring.config.activate.on-profile=production
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
✅ 配置会从上到下依次加载,后出现的属性会覆盖前面的同名属性。
8.4. Profile 组
Spring Boot 2.4 引入了 Profile 组功能,可以将多个 Profile 聚合成一个组:
spring.profiles.group.production=proddb,prodquartz
激活 production
Profile 时,会自动激活 proddb
和 prodquartz
。
9. 总结
本文介绍了如何使用 @Profile
注解定义 Profile,以及如何在不同场景下激活 Profile。并通过一个简单的实际例子展示了 Profile 的使用方式。
完整示例代码可参考 GitHub 项目。