什么是Profiles
介绍
随着软件开发变得越来越复杂,应用程序往往需要在不同的环境中运行,比如开发、测试、生产等。每个环境可能对配置有不同的需求。手动管理这些差异化的配置不仅容易出错,而且效率低下。为了解决这个问题,Spring框架引入了Profiles的概念,它允许开发者根据不同的环境来激活特定的配置设置。
Spring Profiles 是Spring框架提供的一种机制,用来解决多环境配置问题。通过定义不同的profiles,可以在同一套代码库中针对不同的运行时环境(如开发、测试、生产)指定不同的配置属性,这样就提供了一种方式允许我们指定在特定环境下只加载对应的程序配置,每一种环境配置对应一个 Profile,只有当前 Profile 处于激活状态时,才会将该 Profile 所对应的配置和 Bean 加载到 Spring 程序中。这样做的好处是能够保持代码的一致性,同时又能灵活地适应各种环境的变化。
Spring Profiles 就是针对应用程序,不同环境需要不同配置加载的一种解决方案。
Profile 的概念其实很早在 Spring Framework 就有了,在 Spring Framework
3.1 版本引入了注解 @Profile
和 Environment
环境配置的抽象,只是在 Spring Boot 框架里再进一步将 Profiles
功能进行扩展,使它也成为了 Spring Boot 特性之一,为此单独在 官方文档
25. Profiles 一节里介绍,文档里把 Spring Boot Profiles 也叫做 Spring
Profiles。
当然 Spring 允许多个 Profile 处于激活状态,在需要激活环境对应配置时,指定多个 Profile。
在实际开发中,Profile 可以用来实现以下几种功能:
- 区分不同的环境,例如开发环境、测试环境和生产环境。
- 配置不同的数据库连接信息
- 配置不同的日志级别
使用 Profiles
如何使用
在 Spring Boot 中,Profile 是通过配置文件来实现的。在不同的环境下,可以加载不同的配置文件,从而实现不同的配置逻辑。具体来说,Spring Boot 支持以下几种配置文件:
application.properties
application.yml
application-{profile}.properties
application-{profile}.yml
其中,application.properties
和
application.yml
是通用的配置文件,它们在所有的环境下都会被加载。而
application-{profile}.properties
和
application-{profile}.yml
则是根据不同的 Profile
来加载的配置文件。当应用程序启动时,Spring Boot
会根据当前的环境变量来决定加载哪个配置文件。例如,如果当前环境变量为
dev,则会加载 application-dev.properties
或
application-dev.yml
文件。
我们使用 Profiles 的步骤一般如下:
- 标识环境:指定哪些组件、配置在哪个环境⽣效
- 切换环境:这个环境对应的所有组件和配置就应该⽣效
在 Spring 中,Profiles 用于实现
“环境隔离”(比如区分开发、测试、生产环境的配置),核心有两种使用方式:XML
配置 和 @Profile
注解。
XML 就不细说了,在 XML 配置文件中,通过
<beans profile="环境标识">
来隔离不同环境的 Bean 定义,注意必须使用 Spring XML Beans Schema 4.0+(对应 Spring 3.1+ 版本),否则<beans profile>
会报错。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<!-- 开发环境 Bean -->
<beans profile="dev">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://dev.db:3306/test" />
<!-- 其他开发环境配置 -->
</bean>
</beans>
<!-- 生产环境 Bean -->
<beans profile="prod">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://prod.db:3306/test" />
<!-- 其他生产环境配置 -->
</bean>
</beans>此时激活有两种方式
通过
spring.profiles.active
指定环境1
2
3
4// 代码方式激活
new AnnotationConfigApplicationContext()
.getEnvironment()
.setActiveProfiles("dev");或通过 JVM 参数:
1
-Dspring.profiles.active=prod
@Profile
是更灵活的 注解式 环境隔离方案,支持标注在 类 或 方法 上,任何@Component
,@Configuration
或者@ConfigurationProperties
,决定 Bean 是否在特定环境下生效。容器中的组件都可以被@Profile
标记标注在
@Configuration
类上示例,区分开发和生产环境的配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 开发环境配置类(可以写多个,当 dev 和 test 环境激活时生效)
public class DevConfig {
public DataSource dataSource() {
return new DruidDataSource() {{
setUrl("jdbc:mysql://dev.db:3306/test");
}};
}
}
// 生产环境配置类(仅当 prod 环境激活时生效)
public class ProdConfig {
public DataSource dataSource() {
return new DruidDataSource() {{
setUrl("jdbc:mysql://prod.db:3306/test");
}};
}
}如果标注
@Profile("default")
,是默认 profile,指定在默认环境下生效如果组件没有标注
@Profile
注解,代表任意时刻都生效标注在
@Bean
方法上示例:同一个配置类中,不同环境返回不同 Bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class DataSourceConfig {
// 开发环境 DataSource
public DataSource devDataSource() {
return new DruidDataSource() {{
setUrl("jdbc:mysql://dev.db:3306/test");
}};
}
// 生产环境 DataSource
public DataSource prodDataSource() {
return new DruidDataSource() {{
setUrl("jdbc:mysql://prod.db:3306/test");
}};
}
}组合条件:
@Profile("!prod")
(非生产环境生效)示例:测试、开发环境共用一套配置
1
2
3
4
5
6
7
// 非 prod 环境(如 dev、test)生效
public DataSource nonProdDataSource() {
return new DruidDataSource() {{
setUrl("jdbc:mysql://test.db:3306/test");
}};
}与
application
配置文件配合使用在 Spring Boot 中,通常会结合
application.yml
配置 Profilesapplication-{profile}.properties
可以作为指定环境的配置⽂件,示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 通用配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
# 开发环境配置(application-dev.yml)
spring:
profiles: dev
datasource:
url: jdbc:mysql://dev.db:3306/test
username: dev_user
password: dev_pass
# 生产环境配置(application-prod.yml)
spring:
profiles: prod
datasource:
url: jdbc:mysql://prod.db:3306/test
username: prod_user
password: prod_pass激活这个环境,配置就会⽣效。最终⽣效的所有配置是
application.properties
:主配置⽂件,任意时候都⽣效application-{profile}.properties
:指定环境配置⽂件,激活指定环境⽣效,带profile
的配置文件的优先级 大于 不带的application
激活对应的 Profiles
Spring Profiles 的激活是实现环境隔离的关键环节,以下是各种激活方式的原理与实践
在配置文件中指定(推荐方式)
在 application.yml
中指定:
1 | spring: |
1 | spring.profiles.active=prod |
场景:
- 项目默认环境(如测试环境)可直接写入
application.yml
。 - 配合
application-{profile}.yml
实现环境隔离:
其中,可以实现指定多个环境
1 | spring.profiles.active=dev,test |
配置默认环境
1 | spring.profiles.default=test |
注意:
- 未标注
@Profile
的组件始终生效,不受默认环境影响。 - 若同时存在
spring.profiles.active
和default
,active
优先级更高。
命令行参数激活(动态覆盖)
语法:
1 | # 单环境激活 |
场景:
- 生产部署时临时切换环境(如从测试环境切到预发环境)。
- 容器化部署时通过环境变量传递:
编程式动态激活(API 方式)
1 | import org.springframework.boot.SpringApplication; |
或者在启动类中也可以指定
1 | public static void main(String[] args) { |
场景:
框架 / 中间件需要根据运行时条件动态选择环境(如根据服务器 IP 判断生产 / 测试环境)。
单元测试中临时切换 Profile(配合
@ActiveProfiles
注解)。
激活方式的优先级(从高到低)
命令行参数:
--spring.profiles.active=prod
(最高优先级,可覆盖一切)编程式激活:
app.setAdditionalProfiles(...)
(次高优先级)系统属性:
-Dspring.profiles.active=prod
环境变量:
SPRING_PROFILES_ACTIVE=prod
application.yml
中的spring.profiles.active
(默认配置)spring.profiles.default
(最低优先级,仅当无 active 时生效)
配置文件加载顺序
Spring Boot 按以下顺序加载配置,后加载的会覆盖先加载的:
- 当前目录下的
application.yml
- 类路径下的
application.yml
- 当前目录下的
application-{profile}.yml
- 类路径下的
application-{profile}.yml
环境包含问题:
spring.profiles.active
和spring.profiles.default
这两条配置项目只能⽤到 ⽆ profile 的⽂件中,如果在application-{profiles}.yaml
这种带 profiles 的配置文件中编写就是⽆效的也可以额外添加⽣效⽂件,⽽不是激活替换。⽐如:
1
2spring.profiles.include[0]=common
spring.profiles.include[1]=local1
2
3
4
5
6spring:
profiles:
active: prod
include:
- common # 叠加common配置
- logging # 叠加logging配置效果:
- 除了
prod
环境的配置,还会加载application-common.yml
和application-logging.yml
。 - 适用于公共配置与环境配置分离的场景(如公共日志配置、公共服务配置)。
- 除了
Profile 分组问题:
在实际开发中,一个应用可能涉及多个维度的配置切换(如环境、功能模块),此时 Profile 分组 能更高效地管理复杂配置。Profile 分组允许将多个 Profile 归为一组,通过激活组名来批量启用相关配置
Profile 分组本质是将多个 Profile 逻辑聚合,实现 “一键激活多个关联配置”。
1 | # 开发环境分组配置 |
1 | # 激活开发环境分组配置 |
激活 dev
时,自动启用
base
、redis
、dev-logging
三个
Profile 的配置。
Profile 分组支持嵌套,即一个分组可包含另一个分组
优先级规则
- 同层级 Profile:后加载的覆盖先加载的(如
dev
覆盖base
中的重复配置)。 - 嵌套 Profile:子分组的配置会合并到父分组中,若冲突,以最内层为准。