查看SpringApplication.run方法的源代码,其源代码如下所示:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
ArrayList exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters1;
try {
DefaultApplicationArguments ex = new DefaultApplicationArguments(args);
//准备Spring的运行环境信息
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, ex);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
exceptionReporters1 = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, new Object[]{context});
//准备上下文,包括设置父上下文
this.prepareContext(context, environment, listeners, ex, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, ex);
stopWatch.stop();
if(this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, ex);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters1, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
//根据上下文创建环境
Object environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
listeners.environmentPrepared((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if(!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
private ConfigurableEnvironment getOrCreateEnvironment() {
if(this.environment != null) {
return this.environment;
} else {
//根据webApplicationType类型创建不同的环境,webApplicationType是根据WebApplicationType.deduceFromClasspath()方法来确定的,
switch(null.$SwitchMap$org$springframework$boot$WebApplicationType[this.webApplicationType.ordinal()]) {
case 1:
return new StandardServletEnvironment();//基于servlet的web server
case 2:
return new StandardReactiveWebEnvironment();//基于reactive的web server
default:
return new StandardEnvironment();
}
}
}
以StandardServletEnvironment的环境为例,其父类AbstractEnvironment的构造函数调用了customizePropertySources方法,StandardServletEnvironment重写了customizePropertySources方法,将servletConfigInitParams,servletContextInitParams,jndiProperties,systemProperties,systemEnvironment等PropertySource按顺序添加到propertySources集合中。
public AbstractEnvironment() {
this.propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
this.customizePropertySources(this.propertySources);
}
StandardServletEnvironment.customizePropertySources
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
propertySources.addLast(new StubPropertySource("servletContextInitParams"));
if(JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource("jndiProperties"));
}
super.customizePropertySources(propertySources);
}
StandardEnvironment.customizePropertySources
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new PropertiesPropertySource("systemProperties", this.getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
}
然后调用SpringApplication.configureEnvironment方法,设置defaultProperties和commandLineArgs的PropertySource到propertySources,commandLineArgs放到集合的最前面
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if(this.addConversionService) {
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService)conversionService);
}
this.configurePropertySources(environment, args);
this.configureProfiles(environment, args);
}
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 = "commandLineArgs";
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 {
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}
此时PropertySources的配置文件顺序如下:
commandLineArgs
servletConfigInitParams
servletContextInitParams
jndiProperties
systemProperties
systemEnvironment
defaultProperties
基本的环境配置文件准备完成之后,调用SpringApplicationRunListeners.environmentPrepared方法,发布ApplicationEnvironmentPreparedEvent事件,通知对应的监听器,主要看ConfigFileApplicationListener,ConfigFileApplicationListener.onApplicationEnvironmentPreparedEvent方法监听了ApplicationEnvironmentPreparedEvent事件,ConfigFileApplicationListener即是EnvironmentPostProcessor,又是ApplicationListener。
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
//通过SPI机制,获得配置的所有EnvironmentPostProcessor的实现类。
List postProcessors = this.loadPostProcessors();
//ConfigFileApplicationListener也是EnvironmentPostProcessor的实现类,将自己加入到postProcessors 中
postProcessors.add(this);
//对postProcessors 进行排序
AnnotationAwareOrderComparator.sort(postProcessors);
Iterator var3 = postProcessors.iterator();
while(var3.hasNext()) {
EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
//调用EnvironmentPostProcessor实现类的postProcessEnvironment方法,主要查看ConfigFileApplicationListener.postProcessEnvironment方法
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
}
List<EnvironmentPostProcessor> loadPostProcessors() {
return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, this.getClass().getClassLoader());
}
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
this.addPropertySources(environment, application.getResourceLoader());
}
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
//将RandomValuePropertySource加入到环境的PropertySources集合中,放在systemEnvironment之后
RandomValuePropertySource.addToEnvironment(environment);
(new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
}
void load() {
FilteredPropertySource.apply(this.environment, "defaultProperties", ConfigFileApplicationListener.LOAD_FILTERED_PROPERTY, (defaultProperties) -> {
this.profiles = new LinkedList();
this.processedProfiles = new LinkedList();
this.activatedProfiles = false;
this.loaded = new LinkedHashMap();
this.initializeProfiles();
while(!this.profiles.isEmpty()) {
ConfigFileApplicationListener.Profile profile = (ConfigFileApplicationListener.Profile)this.profiles.poll();
if(this.isDefaultProfile(profile)) {
this.addProfileToEnvironment(profile.getName());
}
//根据激活的profile名称,加载对应的配置文件
this.load(profile, this::getPositiveProfileFilter, this.addToLoaded(MutablePropertySources::addLast, false));
this.processedProfiles.add(profile);
}
this.load((ConfigFileApplicationListener.Profile)null, this::getNegativeProfileFilter, this.addToLoaded(MutablePropertySources::addFirst, true));
this.addLoadedPropertySources();
this.applyActiveProfiles(defaultProperties);
});
}
private void load(ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
//通过getSearchLocations方法,获取配置文件的目录,默认classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/
this.getSearchLocations().forEach((location) -> {
boolean isDirectory = location.endsWith("/");
//通过getSearchNames方法获取spring.config.name的配置值,默认为application
Set names = isDirectory?this.getSearchNames():ConfigFileApplicationListener.NO_SEARCH_NAMES;
names.forEach((name) -> {
//根据文件路径location,文件名称name,激活的配置profile加载配置文件
this.load(location, name, profile, filterFactory, consumer);
});
});
}
private void load(String location, String name, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
if(!StringUtils.hasText(name)) {
Iterator var13 = this.propertySourceLoaders.iterator();
PropertySourceLoader var14;
do {
if(!var13.hasNext()) {
throw new IllegalStateException("File extension of config file location \'" + location + "\' is not known to any PropertySourceLoader. If the location is meant to reference a directory, it must end in \'/\'");
}
var14 = (PropertySourceLoader)var13.next();
} while(!this.canLoadFileExtension(var14, location));
this.load(var14, location, profile, filterFactory.getDocumentFilter(profile), consumer);
} else {
HashSet processed = new HashSet();
//获取配置文件解析器,主要有PropertiesPropertySourceLoader(解析Properties和xml类型文件)和YamlPropertySourceLoader(解析yml和yaml文件)
Iterator loader = this.propertySourceLoaders.iterator();
while(loader.hasNext()) {
PropertySourceLoader loader1 = (PropertySourceLoader)loader.next();
//PropertiesPropertySourceLoader.getFileExtensions的值为Properties、xml,YamlPropertySourceLoader为yml、yaml
String[] var9 = loader1.getFileExtensions();
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String fileExtension = var9[var11];
if(processed.add(fileExtension)) {
//根据文件路径location,文件名称name,文件后缀fileExtension,激活的配置profile加载配置文件
this.loadForFileExtension(loader1, location + name, "." + fileExtension, profile, filterFactory, consumer);
}
}
}
}
}
private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
ConfigFileApplicationListener.DocumentFilter defaultFilter = filterFactory.getDocumentFilter((ConfigFileApplicationListener.Profile)null);
ConfigFileApplicationListener.DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile);
if(profile != null) {
String profileSpecificFile = prefix + "-" + profile + fileExtension;
this.load(loader, profileSpecificFile, profile, defaultFilter, consumer);
this.load(loader, profileSpecificFile, profile, profileFilter, consumer);
Iterator var10 = this.processedProfiles.iterator();
while(var10.hasNext()) {
//遍历激活的Profile,如dev或者test
ConfigFileApplicationListener.Profile processedProfile = (ConfigFileApplicationListener.Profile)var10.next();
if(processedProfile != null) {
//拼接配置文件的路径和名称
String previouslyLoaded = prefix + "-" + processedProfile + fileExtension;
this.load(loader, previouslyLoaded, profile, profileFilter, consumer);
}
}
}
this.load(loader, prefix + fileExtension, profile, profileFilter, consumer);
}
private void load(PropertySourceLoader loader, String location, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilter filter, ConfigFileApplicationListener.DocumentConsumer consumer) {
Resource[] resources = this.getResources(location);
Resource[] var7 = resources;
int var8 = resources.length;
for(int var9 = 0; var9 < var8; ++var9) {
Resource resource = var7[var9];
try {
StringBuilder ex;
//判断文件是否存在
if(resource != null && resource.exists()) {
if(!StringUtils.hasText(StringUtils.getFilenameExtension(resource.getFilename()))) {
} else {
String var17 = "applicationConfig: [" + this.getLocationName(location, resource) + "]";
//读取配置文件,解析成ConfigFileApplicationListener.Document类
List var18 = this.loadDocuments(loader, var17, resource);
if(CollectionUtils.isEmpty(var18)) {
if(this.logger.isTraceEnabled()) {
StringBuilder loaded = this.getDescription("Skipped unloaded config ", location, resource, profile);
this.logger.trace(loaded);
}
} else {
ArrayList var19 = new ArrayList();
Iterator description1 = var18.iterator();
while(description1.hasNext()) {
ConfigFileApplicationListener.Document document = (ConfigFileApplicationListener.Document)description1.next();
if(filter.match(document)) {
this.addActiveProfiles(document.getActiveProfiles());
this.addIncludedProfiles(document.getIncludeProfiles());
var19.add(document);
}
}
Collections.reverse(var19);
if(!var19.isEmpty()) {
var19.forEach((document) -> {
//循环调用ConfigFileApplicationListener.DocumentConsumer的accept方法,即addToLoaded返回的对象。
consumer.accept(profile, document);
});
}
}
}
}
}
}
}
private ConfigFileApplicationListener.DocumentConsumer addToLoaded(BiConsumer<MutablePropertySources, PropertySource<?>> addMethod, boolean checkForExisting) {
return (profile, document) -> {
if(checkForExisting) {
Iterator merged = this.loaded.values().iterator();
while(merged.hasNext()) {
MutablePropertySources merged1 = (MutablePropertySources)merged.next();
if(merged1.contains(document.getPropertySource().getName())) {
return;
}
}
}
//获取已经存在的profile对应的MutablePropertySources
MutablePropertySources merged2 = (MutablePropertySources)this.loaded.computeIfAbsent(profile, (k) -> {
return new MutablePropertySources();
});
//即调用MutablePropertySources的addFirst方法,将document中解析出的PropertySource,保存到profile对应的MutablePropertySources的最前面
addMethod.accept(merged2, document.getPropertySource());
};
}
配置文件解析完成之后,调用this.addLoadedPropertySources(), 遍历loaded中的所有MutablePropertySources 中的所有PropertySource,保存到environment的MutablePropertySources 中;
private void addLoadedPropertySources() {
MutablePropertySources destination = this.environment.getPropertySources();
ArrayList loaded = new ArrayList(this.loaded.values());
Collections.reverse(loaded);
String lastAdded = null;
HashSet added = new HashSet();
Iterator var5 = loaded.iterator();
//遍历解析出来的保存在loaded中的MutablePropertySources
while(var5.hasNext()) {
MutablePropertySources sources = (MutablePropertySources)var5.next();
Iterator var7 = sources.iterator();
//遍历每一个MutablePropertySources 中的
while(var7.hasNext()) {
PropertySource source = (PropertySource)var7.next();
if(added.add(source.getName())) {
//将配置source 保存到环境对应的MutablePropertySources的最后
this.addLoadedPropertySource(destination, lastAdded, source);
lastAdded = source.getName();
}
}
}
}
private void addLoadedPropertySource(MutablePropertySources destination, String lastAdded, PropertySource<?> source) {
if(lastAdded == null) {
if(destination.contains("defaultProperties")) {
destination.addBefore("defaultProperties", source);
} else {
destination.addLast(source);
}
} else {
destination.addAfter(lastAdded, source);
}
}
在上面的解析中只是解析了 带application前缀的配置文件,对于bootstrap前缀的配置文件是在BootstrapApplicationListener中解析的,BootstrapApplicationListener是ApplicationListener子类,监听ApplicationEnvironmentPreparedEvent,BootstrapApplicationListener的内部私有类AncestorInitializer实现了ApplicationContextInitializer
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { //获取上下文的的环境 ConfigurableEnvironment environment = event.getEnvironment(); if(((Boolean)environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class, Boolean.valueOf(true))).booleanValue()) { if(!environment.getPropertySources().contains("bootstrap")) { ConfigurableApplicationContext context = null; String configName = environment.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}"); //获取所有的ApplicationContextInitializer对象迭代遍历 Iterator var5 = event.getSpringApplication().getInitializers().iterator(); while(var5.hasNext()) { ApplicationContextInitializer initializer = (ApplicationContextInitializer)var5.next(); if(initializer instanceof ParentContextApplicationContextInitializer) { //获取已经存在的bootstrapContext上下文 context = this.findBootstrapContext((ParentContextApplicationContextInitializer)initializer, configName); } } if(context == null) { //开启一个新的上下文,bootstrapContext上下文在启动的上下文之前完成 context = this.bootstrapServiceContext(environment, event.getSpringApplication(), configName); event.getSpringApplication().addListeners(new ApplicationListener[]{new BootstrapApplicationListener.CloseContextOnFailureApplicationListener(context)}); } this.apply(context, event.getSpringApplication(), environment); } } }
private ConfigurableApplicationContext bootstrapServiceContext(ConfigurableEnvironment environment, SpringApplication application, String configName) { //创建一个新的标准环境 StandardEnvironment bootstrapEnvironment = new StandardEnvironment(); //获取环境的配置文件 MutablePropertySources bootstrapProperties = bootstrapEnvironment.getPropertySources(); Iterator configLocation = bootstrapProperties.iterator(); while(configLocation.hasNext()) { PropertySource configAdditionalLocation = (PropertySource)configLocation.next(); bootstrapProperties.remove(configAdditionalLocation.getName()); } String configLocation1 = environment.resolvePlaceholders("${spring.cloud.bootstrap.location:}"); String configAdditionalLocation1 = environment.resolvePlaceholders("${spring.cloud.bootstrap.additional-location:}"); HashMap bootstrapMap = new HashMap(); //设置spring.config.name的配置为bootstrap bootstrapMap.put("spring.config.name", configName); bootstrapMap.put("spring.main.web-application-type", "none"); if(StringUtils.hasText(configLocation1)) { bootstrapMap.put("spring.config.location", configLocation1); } if(StringUtils.hasText(configAdditionalLocation1)) { bootstrapMap.put("spring.config.additional-location", configAdditionalLocation1); } //将bootstrapMap配置文件的优先级放到最前面 bootstrapProperties.addFirst(new MapPropertySource("bootstrap", bootstrapMap)); Iterator builder = environment.getPropertySources().iterator(); //遍历环境中已经存在的配置文件,重新保存到bootstrapProperties中,按顺序放到bootstrapMap后面 while(builder.hasNext()) { PropertySource builderApplication = (PropertySource)builder.next(); if(!(builderApplication instanceof StubPropertySource)) { bootstrapProperties.addLast(builderApplication); } } //设置新上下文的参数 SpringApplicationBuilder builder1 = (new SpringApplicationBuilder(new Class[0])).profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF).environment(bootstrapEnvironment).registerShutdownHook(false).logStartupInfo(false).web(WebApplicationType.NONE); SpringApplication builderApplication1 = builder1.application(); if(builderApplication1.getMainApplicationClass() == null) { builder1.main(application.getMainApplicationClass()); } if(environment.getPropertySources().contains("refreshArgs")) { builderApplication1.setListeners(this.filterListeners(builderApplication1.getListeners())); } builder1.sources(new Class[]{BootstrapImportSelectorConfiguration.class}); //启动上下文,此时spring.config.name的配置为bootstrap,所以会读取bootstrap文件名称的相关配置; ConfigurableApplicationContext context = builder1.run(new String[0]); context.setId("bootstrap"); //将BootstrapApplicationListener.AncestorInitializer添加到application上下文中, this.addAncestorInitializer(application, context); bootstrapProperties.remove("bootstrap"); this.mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties); return context; }
上面已经将带bootstrap前缀的配置文件加载到了bootstrapContext父上下文中,然后当前上下文applicationContext调用SpringApplication.applyInitializers方法
protected void applyInitializers(ConfigurableApplicationContext context) { Iterator var2 = this.getInitializers().iterator(); while(var2.hasNext()) { ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next(); Class requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
查看AncestorInitializer的initialize方法的,其创建了ParentContextApplicationContextInitializer对象,并调用了ParentContextApplicationContextInitializer.initialize方法,将bootstrapEnvironment对应的bootstrapContext上下文作为父上下文设置到当前的applicationContext中,从而将bootstrapEnvironment中的bootstrap相关的配置文件合并到applicationContext中,配置文件的优先级如下
public void initialize(ConfigurableApplicationContext context) { while(context.getParent() != null && context.getParent() != context) { context = (ConfigurableApplicationContext)context.getParent(); } this.reorderSources(context.getEnvironment()); (new ParentContextApplicationContextInitializer(this.parent)).initialize(context); }
public void initialize(ConfigurableApplicationContext applicationContext) { if(applicationContext != this.parent) { applicationContext.setParent(this.parent); applicationContext.addApplicationListener(ParentContextApplicationContextInitializer.EventPublisher.INSTANCE); } }