监听器:ConfigFileApplicationListener、BootstrapApplicationListener
1、系统启动时,调用SpringApplication.run()
2、初始化监听器
//初始化SpringApplicationRunListeners,并且初始化变量listeners,将EventPublishingRunListener存放与listeners中
1)SpringApplicationRunListeners listeners = this.getRunListeners(args);
2)
3)SpringFactoriesLoader.loadSpringFactories()加载META-INF/spring.factories下的配置监听器
3、调用ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);内部调用步骤如下
1)listeners.environmentPrepared((ConfigurableEnvironment)environment);
监听器的准备工作
2)listener.environmentPrepared(environment);
循环listeners中的监听器,执行environmentPrepared方法,其中加载配置文件的监听器就在循环列表中
3)执行EventPublishingRunListener中的environmentPrepared()方法
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
4)SimpleApplicationEventMulticaster类中的doInvokeListener()方法
5)执行ConfigFiledApplicationListerner类中的onApplicationEvent(event)方法
6)执行ConfigFileApplicationListener中的onApplicationEnviromentPrepareEvent()方法
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
Iterator var3 = postProcessors.iterator();
while(var3.hasNext()) {
EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
}
注意:AnnotationAwareOrderComparator.sort(postProcessors); 对List<EnvironmentPostProcessor>集合进行排序,排序规则按照spring中的注解@Order注解和@Priority注解排序
7)迭代postPrccessors集合,并且执行集合中的postProcessEnvironment方法,重点看ConfigFileApplicationListener类中的postProcessEnvironment方法
其中会添加一个属性源进来ResourceLoader
8)调用load方法加载属性
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
(new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
}
9) load方法中调用apply方法
void load() {
FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
(defaultProperties) -> {
this.profiles = new LinkedList<>();
this.processedProfiles = new LinkedList<>();
this.activatedProfiles = false;
this.loaded = new LinkedHashMap<>();
initializeProfiles();
while (!this.profiles.isEmpty()) {
Profile profile = this.profiles.poll();
if (isDefaultProfile(profile)) {
addProfileToEnvironment(profile.getName());
}
load(profile, this::getPositiveProfileFilter,
addToLoaded(MutablePropertySources::addLast, false));
this.processedProfiles.add(profile);
}
load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
addLoadedPropertySources();
applyActiveProfiles(defaultProperties);
});
}
10) apply方法默认获取defaultProperties属性,如果获取为空,则从上一步中执行函数式编程中的accept方法,下边移步到accept方法一探究竟,首先apply方法中会执行一个初始化方法initializeProfiles,方法中会向profiles中放入null,然后再放入一个"default",用来从外部遍历,遍历为null的时候,加载springboot的默认配置,遍历为“default"时,加载用户配置,从而充分体现了约定大于配置
11)遍历profiles集合,遍历的第一次为null,执行load方法如下
private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
getSearchLocations().forEach((location) -> {
boolean isDirectory = location.endsWith("/");
Set<String> names = isDirectory ? getSearchNames() : NO_SEARCH_NAMES;
names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
});
}
首先执行getSearchLocations方法,获取默认的路径,默认的路径为如果启动参数中有"spring.config.location",则加载spring.config.location中指定的配置文件,否则用默认的DEFAULT_SEARCH_LOCATIONS,
classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/
12)取出Locations为classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/
遍历set,按照先后顺序取配置文件
13)获取配置文件名字,如果配置spring.confing.name的话,则去配置的名字,否则用默认的"application"
14)取到location和name之后,执行load(String location, String name, Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer)方法,加载配置,如下图
15 最终通过以钩子程序的形式调用函数式编程完成属性的赋值
调用Map中的computeIfAbsent,如果不存在profile的key,则添加新的数据,并将value值返回