文章目录
-
- [一、Profile 功能](#一、Profile 功能)
-
- [1. 环境配置文件规则](#1. 环境配置文件规则)
- [2. 激活指定环境](#2. 激活指定环境)
- [3. 配置生效规则](#3. 配置生效规则)
- [4. @Profile 条件配置](#4. @Profile 条件配置)
- [5. Profile 分组](#5. Profile 分组)
- [6. IDEA 配置多环境启动](#6. IDEA 配置多环境启动)
- 二、外部化配置
- 三、配置文件类型详解
-
- [1. Properties 文件](#1. Properties 文件)
- [2. YAML 文件](#2. YAML 文件)
- [3. 关闭命令行参数传递](#3. 关闭命令行参数传递)
- 四、自定义配置类绑定与提示
- [四、面试题 Spring Boot 读取配置文件的 5 种常用方式](#四、面试题 Spring Boot 读取配置文件的 5 种常用方式)
-
- [1、@Value 注解:直接读取单个属性(最简单)](#1、@Value 注解:直接读取单个属性(最简单))
- 2、@ConfigurationProperties:批量绑定配置(推荐)
- [3、Environment 接口:动态获取配置(灵活)](#3、Environment 接口:动态获取配置(灵活))
- 4、@PropertySource:加载自定义配置文件(非默认)
- [5、配置树(Configuration Tree):读取目录式配置(云环境常用)](#5、配置树(Configuration Tree):读取目录式配置(云环境常用))
- 实现步骤
- 6、常见问题与注意事项
一、Profile 功能
Profile 是 Spring Boot 提供的环境隔离功能,可实现不同环境下配置的灵活切换。
1. 环境配置文件规则
- Spring Boot 支持按环境定义配置文件,命名格式为
application-{环境名}.yaml/.properties/.xml - 默认配置文件
application.yaml/.properties适用于所有环境,作为基础配置
2. 激活指定环境
(1)配置文件激活
在默认配置文件中通过 spring.profiles.active 属性指定激活的环境,多个环境用英文逗号分隔
yaml
# application.yaml
spring:
profiles:
active: dev,test # 同时激活 dev 和 test 环境
(2)命令行激活(优先级最高)
启动 Jar 包时通过命令行参数指定环境,同时可直接覆盖配置文件中的属性
bash
java -jar xxx.jar --spring.profiles.active=prod --person.name=haha
3. 配置生效规则
- 默认配置与激活的环境配置同时生效
- 同名配置项,环境配置优先于默认配置,后激活的环境优先于先激活的环境
4. @Profile 条件配置
通过 @Profile 注解可实现类或方法的条件加载,只有当指定环境被激活时,该类才会被 Spring 容器加载
java
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration(proxyBeanMethods = false)
@Profile("production") // 仅在 production 环境激活时生效
public class ProductionConfiguration {
// 业务逻辑
}
- 注解值可以是环境名 或环境组名
- 若通过
@EnableConfigurationProperties注册配置类,@Profile需标注在对应的@Configuration类上
5. Profile 分组
当环境配置过于细粒度时,可通过分组功能将多个相关环境整合为一个逻辑组,简化激活操作
(1)定义分组
在默认配置文件中配置分组关系
yaml
# application.yaml
spring:
profiles:
group:
production: [proddb, prodmq] # production 组包含 proddb 和 prodmq 两个环境
(2)激活分组
激活分组时,组内所有环境会被同时激活
bash
java -jar xxx.jar --spring.profiles.active=production
6. IDEA 配置多环境启动
若 IDEA 中没有 VM 选项框,可通过以下步骤配置:
- 点击启动配置下拉框 →
Edit Configurations - 在
Configuration标签页中,勾选Allow multiple instances允许启动多实例 - 在
Program arguments中输入命令行参数,例如--spring.profiles.active=dev
二、外部化配置
外部化配置指将配置与代码解耦,通过多种外部配置源实现不同环境的适配,核心文档参考:Spring Boot 外部化配置官方文档
1. 外部配置源
Spring Boot 支持多种配置源,常用类型如下:
(1)Properties 文件
采用键值对格式,层级用英文点号分隔
properties
# application.properties
person.age=23
server.port=8083
(2)YAML 文件
采用层级缩进格式,更适合复杂配置结构
yaml
# application.yaml
server:
port: 8082
person:
age: 23
(3)命令行参数
启动时通过 --参数名=值 传递,优先级最高,示例见「激活指定环境」章节
(4)其他配置源
还支持 环境变量、Java 系统属性、JNDI 属性、SPRING_APPLICATION_JSON 等配置源
2. 配置优先级
Spring Boot 按以下顺序加载配置(后面的配置源会覆盖前面的同名配置)
- 默认属性(
SpringApplication.setDefaultProperties设置) @PropertySource注解加载的配置(注意:无法加载logging.*、spring.main.*等早期读取的属性)- 配置数据文件(
application.properties/yaml及其环境变体) RandomValuePropertySource(生成random.*随机属性)- 操作系统环境变量
- Java 系统属性(
System.getProperties()) - JNDI 属性(
java:comp/env) ServletContext初始化参数ServletConfig初始化参数SPRING_APPLICATION_JSON(嵌入在环境变量或系统属性中的 JSON 字符串)- 命令行参数
- 测试相关属性(
@SpringBootTest的properties属性、@TestPropertySource注解) - Devtools 全局配置(
$HOME/.config/spring-boot目录,仅 Devtools 激活时生效)
3. 配置文件查找位置
Spring Boot 启动时,会自动从以下位置加载 application.properties/yaml 文件,位置越靠后优先级越高
- 类路径内部
- 类路径根目录(
resources目录) - 类路径
/config子目录
- 类路径根目录(
- 当前目录(相对于 Jar 包所在目录)
- Jar 包所在目录
- Jar 包所在目录的
/config子目录 /config子目录的直接子目录
4. 配置文件加载顺序
- 当前 Jar 包内部的
application.properties/yaml - 当前 Jar 包内部的
application-{profile}.properties/yaml - 外部 Jar 包的
application.properties/yaml - 外部 Jar 包的
application-{profile}.properties/yaml
核心规则:指定环境配置优先于默认配置,外部配置优先于内部配置,后加载的配置覆盖先加载的同名配置
三、配置文件类型详解
1. Properties 文件
- 语法:
key=value,层级用.分隔 - 编码:默认 ISO-8859-1,可通过
spring.config.encoding指定编码格式 - 特点:语法简单,兼容性好,但复杂层级配置可读性较差
2. YAML 文件
YAML 是一种以数据为中心的配置格式,相比 Properties 更适合复杂层级结构
(1)基本语法
- 键值对格式:
key: value,冒号后必须加空格 - 大小写敏感
- 用空格缩进表示层级关系,不允许使用 Tab 键
- 缩进空格数不固定,相同层级元素左对齐即可
- 注释:
#开头的行表示注释 - 字符串:默认无需引号;双引号会转义特殊字符(如
\n会被解析为换行符);单引号不转义特殊字符
(2)支持的数据类型
-
字面量:单个、不可再分的值(字符串、数字、布尔值、日期、null)
yamlstr: hello world num: 123 bool: true date: 2024-01-01 nullVal: ~ # 表示 null -
对象:键值对的集合,支持两种写法
yaml# 多行写法 person: name: zhangsan age: 20 # 行内写法 person: {name: zhangsan, age: 20} -
数组:一组有序的值,支持两种写法
yaml# 多行写法 list: - apple - banana - orange # 行内写法 list: [apple, banana, orange]
(3)属性引用
可通过 ${key} 引用已定义的属性,支持默认值 ${key:默认值}
yaml
spring:
datasource:
name: mydb
url: jdbc:mysql://localhost:3306/${spring.datasource.name:defaultdb}
(4)注意事项
-
YAML 对数字格式敏感,以
0开头的数字会被解析为八进制,以0x开头的会被解析为十六进制 -
若需将数字作为字符串处理,必须用引号包裹
yaml# 正确写法:作为字符串 password: "012345" # 错误写法:会被解析为八进制数字 52428 password: 012345
3. 关闭命令行参数传递
若不需要通过命令行传递参数,可修改 Spring Boot 入口类,启动时不传入 args 参数
java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
// 不传入 args 参数,关闭命令行参数解析
SpringApplication.run(MyApplication.class);
}
}
四、自定义配置类绑定与提示
1. 自定义配置类绑定
通过 @ConfigurationProperties 注解可将配置文件中的属性绑定到自定义 Java 类,实现类型安全的配置管理
java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "person") // 绑定前缀为 person 的属性
public class PersonProperties {
private String name;
private Integer age;
// Getter 和 Setter 方法
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
}
2. 开启配置提示
自定义配置类默认没有 IDE 自动提示,需导入配置处理器依赖解决
(1)添加依赖
xml
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
(2)排除打包依赖
为避免配置处理器被打包到最终的 Jar 包中,需在 Maven 插件中配置排除
xml
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
四、面试题 Spring Boot 读取配置文件的 5 种常用方式
Spring Boot 读取配置文件的核心是利用其外部化配置机制,支持多种灵活方式,覆盖简单属性、批量绑定、复杂场景等需求,以下是具体实现方法和注意事项:
1、@Value 注解:直接读取单个属性(最简单)
适用场景
快速读取单个简单配置项(如端口、用户名、常量等),无需批量绑定。
实现步骤
- 配置文件(以 YAML 为例):
yaml
# application.yaml
server:
port: 8080
person:
name: 张三
age: 25
address: 北京
- 代码中注入:
java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class MyComponent {
// 直接读取单个属性,支持默认值(找不到配置时用默认值)
@Value("${server.port}")
private Integer serverPort;
@Value("${person.name}")
private String personName;
// 配置不存在时,使用默认值 "上海"
@Value("${person.address:上海}")
private String personAddress;
// 测试方法
public void printConfig() {
System.out.println("端口:" + serverPort);
System.out.println("姓名:" + personName);
System.out.println("地址:" + personAddress);
}
}
注意事项
- 语法格式:
@Value("${配置键:默认值}"),默认值可选(冒号后为默认值); - 支持松散绑定吗?有限支持!仅当配置键用短横线命名 (如
person.user-name),注解中用@Value("${person.user-name}")才能匹配,驼峰命名(person.userName)不兼容; - 不支持复杂类型(如对象、数组),仅适用于字符串、数字、布尔值等字面量。
2、@ConfigurationProperties:批量绑定配置(推荐)
适用场景
读取多个相关配置项(如一个对象的多个属性),实现类型安全绑定,替代多个 @Value 注解。
实现步骤
- 配置文件(YAML):
yaml
# application.yaml
person:
name: 李四
age: 30
address: 广州
hobbies: [篮球, 读书] # 数组
contact:
phone: 13800138000
email: lisi@example.com # 嵌套对象
- 定义配置类(批量绑定):
java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
// 绑定前缀为 "person" 的所有配置
@Component
@ConfigurationProperties(prefix = "person")
public class PersonProperties {
// 字段名与配置键一致(支持松散绑定:hobbies = person.hobbies = person.hob-bies)
private String name;
private Integer age;
private String address;
private List<String> hobbies; // 数组/集合类型
private Contact contact; // 嵌套对象类型
// 必须提供 Getter 和 Setter 方法(否则绑定失败)
// Getter + Setter 省略...
// 嵌套对象类
public static class Contact {
private String phone;
private String email;
// Getter + Setter 省略...
}
}
- 使用配置类:
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyService {
@Autowired
private PersonProperties personProperties;
public void printPersonConfig() {
System.out.println("姓名:" + personProperties.getName());
System.out.println("爱好:" + personProperties.getHobbies());
System.out.println("手机号:" + personProperties.getContact().getPhone());
}
}
核心优势
- 支持松散绑定:配置键可写
person.user-name(短横线)、person.userName(驼峰)、person.user_name(下划线),字段名用驼峰(userName)即可匹配; - 支持复杂类型:数组、集合、嵌套对象等自动绑定,无需手动转换;
- 类型安全:字段类型与配置自动匹配(如配置
age: 30自动转为Integer); - IDE 提示:导入
spring-boot-configuration-processor依赖后,配置文件会有语法提示(避免写错键名)。
注意事项
- 必须加
@Component(或通过@EnableConfigurationProperties激活),否则 Spring 无法扫描到; - 字段必须提供 Getter 和 Setter 方法(绑定依赖 JavaBean 规范);
- 前缀
prefix必须用短横线命名 (如person.contact,不能写personContact)。
3、Environment 接口:动态获取配置(灵活)
适用场景
需要动态获取配置(如根据条件读取不同键的配置),或不确定配置键的固定名称。
实现步骤
- 配置文件(Properties 为例):
properties
# application.properties
app.id=APP_001
app.mode=prod
app.version=2.0.0
- 注入 Environment 接口:
java
import org.springframework.core.env.Environment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class EnvConfigReader {
@Autowired
private Environment env;
public void readConfig() {
// 读取配置,参数为配置键
String appId = env.getProperty("app.id");
String appMode = env.getProperty("app.mode");
// 读取并指定类型(自动转换为 Integer)
Integer appVersion = env.getProperty("app.version", Integer.class);
// 读取不存在的配置,返回默认值 "1.0.0"
String fallbackVersion = env.getProperty("app.backup.version", "1.0.0");
System.out.println("应用ID:" + appId);
System.out.println("运行模式:" + appMode);
System.out.println("版本号:" + appVersion);
System.out.println("备用版本:" + fallbackVersion);
}
}
核心特点
- 支持动态键:可通过变量拼接配置键(如
env.getProperty("app." + type)); - 支持类型转换:
getProperty(String key, Class<T> type)自动转换为指定类型; - 支持默认值:
getProperty(String key, String defaultValue)或getProperty(String key, Class<T> type, T defaultValue); - 支持松散绑定吗?不支持!配置键必须与文件中完全一致(如文件中是
app.user-name,就不能用app.userName读取)。
4、@PropertySource:加载自定义配置文件(非默认)
适用场景
默认配置文件(application.yaml/application.properties)外,还需要加载自定义配置文件(如 config/user.properties、config/db.yaml)。
实现步骤(加载自定义 Properties 文件)
- 自定义配置文件(
resources/config/user.properties):
properties
# resources/config/user.properties
user.id=1001
user.name=王五
user.age=28
- 加载并绑定:
java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
// 加载自定义配置文件(classpath 表示 resources 目录)
@Component
@PropertySource(value = "classpath:config/user.properties", encoding = "UTF-8")
@ConfigurationProperties(prefix = "user") // 绑定前缀 "user"
public class UserProperties {
private Integer id;
private String name;
private Integer age;
// Getter + Setter 省略...
}
注意事项
- 编码问题:若配置文件有中文,需指定
encoding = "UTF-8"(默认 ISO-8859-1,会乱码); - 支持 YAML 文件吗?默认不支持!
@PropertySource仅支持.properties文件,若要加载自定义 YAML 文件,需自定义PropertySourceFactory(后续补充); - 优先级:自定义文件的配置优先级低于默认配置文件(
application.yaml),同名配置会被默认文件覆盖。
扩展:加载自定义 YAML 文件
需自定义工厂类,让 @PropertySource 支持 YAML:
- 自定义工厂类:
java
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import java.io.IOException;
public class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
// 用 Spring 提供的 YamlPropertySourceLoader 加载 YAML 文件
return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource())
.get(0);
}
}
- 加载自定义 YAML 文件(
resources/config/db.yaml):
yaml
# resources/config/db.yaml
db:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: 123456
- 绑定配置:
java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@PropertySource(value = "classpath:config/db.yaml", factory = YamlPropertySourceFactory.class, encoding = "UTF-8")
@ConfigurationProperties(prefix = "db")
public class DbProperties {
private String url;
private String username;
private String password;
// Getter + Setter 省略...
}
5、配置树(Configuration Tree):读取目录式配置(云环境常用)
适用场景
Kubernetes 挂载 ConfigMaps/Secrets、Docker Secrets 等场景,配置以"目录-文件"形式存储(文件名=配置键,文件内容=配置值)。
实现步骤
-
假设 Kubernetes 挂载配置到
/etc/config/myapp/目录,目录结构:/etc/config/myapp/
├── username.txt (内容:admin)
├── password.txt (内容:123456)
└── db/
├── url.txt (内容:jdbc:mysql://localhost:3306/mydb)
└── driver.txt (内容:com.mysql.cj.jdbc.Driver) -
配置文件中导入配置树:
yaml
# application.yaml
spring:
config:
import: optional:configtree:/etc/config/myapp/ # 导入目录式配置
- 绑定配置类:
java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "myapp")
public class MyappConfig {
private String username; // 对应 /etc/config/myapp/username.txt
private String password; // 对应 /etc/config/myapp/password.txt
private Db db; // 对应 /etc/config/myapp/db/ 目录
// Getter + Setter 省略...
public static class Db {
private String url; // 对应 /etc/config/myapp/db/url.txt
private String driver; // 对应 /etc/config/myapp/db/driver.txt
// Getter + Setter 省略...
}
}
核心特点
- 导入语法:
configtree:目录路径,optional:前缀表示目录不存在也不报错; - 配置键规则:目录名+文件名组成配置键(如
db.url=db目录 +url文件); - 适用场景:云环境敏感配置(如密码),避免暴露为环境变量,通过文件挂载安全读取。
6、常见问题与注意事项
-
配置键写错了怎么办?
@Value会直接抛出IllegalArgumentException(找不到配置),除非设置了默认值;@ConfigurationProperties不会报错,字段值为null(可通过@Validated注解校验,强制必填)。
-
中文乱码怎么解决?
- Properties 文件:指定编码为 UTF-8(
@PropertySource(encoding = "UTF-8")); - YAML 文件:默认 UTF-8 编码,无需额外配置(确保文件本身是 UTF-8 格式)。
- Properties 文件:指定编码为 UTF-8(
-
不同配置源的优先级
命令行参数 > 环境变量 > 外部配置文件 > 内部配置文件 > 自定义配置文件(
@PropertySource),后加载的配置会覆盖先加载的同名配置。
文章结束,喜欢就给个一键三连吧,你的肯定是我最大的动力,点赞上一千我就是脑瘫也出下章