先展示下官方外部化配置文档
点击查看官方链接
配置优先级如下截图,序号越小优先级越高
跟踪下源码
- org.springframework.boot.SpringApplication#run(java.lang.String…) 方法开始
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
....
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 准备环境变量
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
....
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
....
return context;
}
- org.springframework.boot.SpringApplication#prepareEnvironment 方法
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// 1.创建环境变量
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 2.将命令行中的变量加载到environment中
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 3. 广播事件加载配置变量,如application.properties就是由ConfigFileApplicationListener监听到事件后加载的
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
- org.springframework.boot.SpringApplication#getOrCreateEnvironment 方法
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
// 我配置的tomcat web环境,所以会走到这里
//StandardServletEnvironment 的父类AbstractEnvironment 构造函数中会调用子类的
//org.springframework.web.context.support.StandardServletEnvironment#customizePropertySources方法
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
- org.springframework.web.context.support.StandardServletEnvironment#customizePropertySources 方法
将外部配置servletConfigInitParams servletContextInitParams jndiProperties
systemProperties systemEnvironment 加到MutablePropertySources 中,正如官方文档中所列的
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
}
super.customizePropertySources(propertySources);
}
- 命令行中的变量加载到environment中
org.springframework.boot.SpringApplication#configureEnvironment 方法内调用的org.springframework.boot.SpringApplication#configurePropertySources 方法加载命令行变量
protected void configurePropertySources(ConfigurableEnvironment environment,
String[] args) {
MutablePropertySources sources = environment.getPropertySources();
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
sources.addLast(
new MapPropertySource("defaultProperties", this.defaultProperties));
}
if (this.addCommandLineProperties && args.length > 0) {
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
// 如果已经包含,则替换命令行变量
if (sources.contains(name)) {
PropertySource<?> source = sources.get(name);
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(new SimpleCommandLinePropertySource(
"springApplicationCommandLineArgs", args));
composite.addPropertySource(source);
// 替换
sources.replace(name, composite);
}
else {
// 因为是addFirst,所以命令行参数的优先级会高一些
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}
而这些属性是怎么被使用的就要回到spring framework的org.springframework.context.support.PropertySourcesPlaceholderConfigurer#postProcessBeanFactory 工厂后处理器,会解析替换${ }标识的变量
而是工厂后处理器是有org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors 方法调用开始的,这就又回到了spring 的refresh方法