在spring boot中所有参数都被理解为当前项目运行的环境变量。spring boot环境的初始化操作在ConfigurableApplicationContex
t的创建之前,功实现主要依赖PropertyResolver
和PropertySource
这两个接口。
spring boot项目的非web项目会创建StandardEnvironment
类并完成初始化参数的加载,web项目中则创建的为StandardServletEnvironment
类来完成参数的初始化,其类层次关系如下
PropertyResolver
,额外主要提供属性类型转换(基于org.springframework.core.convert.ConversionService
)功能。PropertyResolver
,额外提供访问和判断profiles的功能。ConfigurablePropertyResolver
和Environment
,并且提供设置激活的profile和默认的profile的功能。ConfigurableEnvironment
,并且提供配置Servlet上下文和Servlet参数的功能。ConfigurableEnvironment
接口,默认属性和存储容器的定义,并且实现了ConfigurableEnvironment
种的方法,并且为子类预留可覆盖了扩展方法。AbstractEnvironment
,非Servlet(Web)环境下的标准Environmen
t实现。StandardEnvironment
,Servlet(Web)环境下的标准Environment
实现。PropertySource
为真实参数存储的地方,Environment
的静态属性和存储容器都是在AbstractEnvironment
中定义的,ConfigurableWebEnvironment
接口提供的getPropertySources()
方法可以获取到返回的MutablePropertySources
实例,然后添加额外的PropertySource
。实际上,Environment
的存储容器就是org.springframework.core.env.PropertySource
的子类集合,如下图:
PropertySource
的常用类层次关系如下:
source
指定为Map实例的PropertySource
实现。source
指定为Map实例的PropertySource
实现,内部的Map
实例由Properties
实例转换而来。PropertiesPropertySource
,source
指定为通过Resource
实例转化为Properties
再转换为Map实例。PropertySource
的一个内部类,source
设置为null
,实际上就是空实现。OriginTrackedValue
,则调用value的getValue
方法循环一直找到最原始的值public ConfigurableApplicationContext run(String... args) {
…………
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//Environment创建和初始化地方,在ApplicationContext创建之前
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
…………
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
…………
}
…………
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 根据webApplicationType来创建StandardServletEnvironment和StandardEnvironment,并初始化一些基础的系统的PropertySource,
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
getOrCreateEnvironment()
执行完成后environment
所初始化的PropertySource
如下:
public void environmentPrepared(ConfigurableEnvironment environment) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
这里的listeners
就一个EventPublishingRunListener
,进入EventPublishingRunListener
的environmentPrepared
方法,
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
可以看到实则广播了ApplicationEnvironmentPreparedEvent
事件,该事件被ConfigFileApplicationListener
所响应
public class ConfigFileApplicationListener
implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
|| ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}
…………
}
重点关注onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event)
方法:
private void onApplicationEnvironmentPreparedEvent(
ApplicationEnvironmentPreparedEvent event) {
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
for (EnvironmentPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessEnvironment(event.getEnvironment(),
event.getSpringApplication());
}
}
这里的postProcessors
包含以下6个postProcessors
,分别以6种不同的方法来加载不同场景下的参数配置:
重点介绍一下ConfigFileApplicationListener
这个 postProcessors
,主要负责加载spring boot 默认预设的配置文件如:classpath:/,classpath:/config/,file:./,file:./config/ 目录下的 application.properties
、application.yml
文件,如果在不同的目录中存在多个配置文件,它的读取顺序是:
onApplicationEnvironmentPreparedEvent
执行完6个postProcessors
后可以看到environment
的PropertySource
又增加了:
第6个为项目跟目录下的自定义配置,断点继续执行,回到SpringApplication.prepareEnvironment(……)
中,接着执行bindToSpringApplication(environment)
将environment绑定到上下文中。
到此为止environment
的参数加载完毕,开始Banner
信息的输出,并创建ApplicationContext
对象。