环境准备与属性源加载
环境准备是 Spring Boot 启动的关键阶段,负责加载和合并所有配置源。
启动入口分析
SpringApplication.run()
Java
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 1. 创建引导上下文
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
// 2. 准备环境 ← 本节重点
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, args);
// 3. 创建应用上下文
context = createApplicationContext();
// ...
}
prepareEnvironment() 核心流程
Java
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext,
ApplicationArguments applicationArguments) {
// 1. 创建环境对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 2. 配置环境
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 3. 附加默认属性源
ConfigurationPropertySources.attach(environment);
// 4. 发布环境准备事件
listeners.environmentPrepared(bootstrapContext, environment);
return environment;
}
Environment 创建
环境类型选择
Java
protected ConfigurableEnvironment createEnvironment() {
return new ApplicationEnvironment(); // Servlet 环境
// Reactive 环境使用 ApplicationReactiveEnvironment
// 非 Web 环境使用 StandardEnvironment
}
环境继承体系
Java
ApplicationEnvironment
↓ extends
StandardServletEnvironment
↓ extends
StandardEnvironment
↓ implements
ConfigurableEnvironment
属性源加载顺序
加载优先级(从高到低)
Java
1. 命令行参数 (CommandLineArguments)
2. JVM 系统属性 (SystemProperties)
3. 操作系统环境变量 (SystemEnvironment)
4. application-{profile}.yml/properties
5. application.yml/properties
6. @ConfigurationProperties 默认值
7. @PropertySource 注解
8. 默认属性 (SpringApplication.setDefaultProperties)
属性源加载源码
YAML
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
MutablePropertySources propertySources = environment.getPropertySources();
// 1. 添加默认属性
if (this.defaultProperties != null) {
propertySources.addLast(
new MapPropertySource("defaultProperties", this.defaultProperties));
}
// 2. 添加命令行参数(最高优先级)
if (args.length > 0) {
propertySources.addFirst(
new SimpleCommandLinePropertySource(args));
}
}
ConfigFileApplicationListener
配置文件加载
Java
// Spring Boot 2.4+ 使用 ConfigDataEnvironmentPostProcessor
public class ConfigFileApplicationListener implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
// 加载 application.yml/properties
load(application, environment);
}
protected void load(ConfigurableEnvironment environment) {
// 按顺序加载:
// 1. file:./config/
// 2. file:./
// 3. classpath:/config/
// 4. classpath:/
}
}
配置文件搜索路径
YAML
# 搜索顺序(后加载覆盖先加载)
file:./config/application.yml # 优先级最高
file:./application.yml
classpath:/config/application.yml
classpath:/application.yml # 优先级最低
Profile 激活机制
Profile 加载
Java
protected void onEnvironmentPrepared(ConfigurableEnvironment environment) {
// 1. 获取激活的 Profile
Set<String> activeProfiles = environment.getActiveProfiles();
// 2. 加载 Profile 配置文件
// application-{profile}.yml
}
Profile 配置方式
Java
# application.yml
spring:
profiles:
active: dev
---
# application-dev.yml
spring:
config:
activate:
on-profile: dev
自定义属性源
实现 PropertySource
properties
public class CustomPropertySource extends PropertySource<Object> {
public CustomPropertySource(String name) {
super(name);
}
@Override
public Object getProperty(String name) {
// 自定义属性获取逻辑
if ("custom.property".equals(name)) {
return "custom-value";
}
return null;
}
}
注册属性源
Java
@Configuration
public class CustomPropertySourceConfig implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
environment.getPropertySources().addFirst(
new CustomPropertySource("customSource"));
}
}
注册到 spring.factories
text
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.CustomPropertySourceConfig
属性绑定机制
Binder 使用
text
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private int port;
// getters/setters
}
// 绑定方式
@Configuration
public class BindingConfig {
@Bean
public AppProperties appProperties(ConfigurableEnvironment environment) {
return Binder.get(environment)
.bind("app", AppProperties.class)
.orElse(new AppProperties());
}
}
注意:命令行参数优先级最高,可用于覆盖配置文件中的值。
要点总结
- 环境准备在 ApplicationContext 创建之前完成
- 属性源按优先级加载,命令行参数优先级最高
- 配置文件按 file → classpath 顺序搜索
- Profile 实现多环境配置切换
- 可通过 EnvironmentPostProcessor 扩展属性源
📝 发现内容有误?点击此处直接编辑