关于
ConfigFileApplicationListener
主要作用就是读取应用的配置文件并add到Environment的PropertySources列表里
Springboot应用在启动的时候准备好了环境后就会触发ApplicationEnvironmentPreparedEvent
事件就开始执行读取配置的逻辑:
首先加载当前激活的Profile列表
然后从默认的classpath:/,classpath:/config/,file:./,file:./config/
这四个目录下
查找默认的application-{profile}名字对应的配置文件,配置文件格式支持两大类(Properties和Yaml)既:.properties .xml .yml .yaml
涉及到的配置参数
- spring.config.name
- spring.config.location
- spring.profiles.active
- spring.profiles.include
- spring.config.additional-location
spring.config.name
可以修改默认的配置文件名字(默认:application),可以指定多个比如 --spring.config.name= application,demo
spring.config.location
可以修改默认的配置文件路径,比如 --spring.config.location= file:///C:/config/ (目录结尾不带“/”会按照文件处理,而不是目录,容易掉坑)
源码阅读收获
通过类的的常量大概知道有什么属性支持配置以及默认参数
//Note the order is from least to most specific (last one wins)
private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
private static final String DEFAULT_NAMES = "application";
private static final Set<String> NO_SEARCH_NAMES = Collections.singleton(null);
private static final Bindable<String[]> STRING_ARRAY = Bindable.of(String[].class);
public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active";
public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include";
public static final String CONFIG_NAME_PROPERTY = "spring.config.name";
public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
public static final String CONFIG_ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location";
它既是一个ApplicationListener,也是一个EnvironmentPostProcessor
阅读源码入口就从他的onApplicationEvent开始跟即可,将自身添加到postProcessor列表里并执行postProcessEnvironment方法,核心逻辑是靠一个Loader内部类
new Loader(environment, resourceLoader).load()
load()方法大概骨架逻辑
public void load() {
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 (profile != null && !profile.isDefaultProfile()) {
addProfileToEnvironment(profile.getName());
}
load(profile, this::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false));
this.processedProfiles.add(profile);
}
resetEnvironmentProfiles(this.processedProfiles);
load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
addLoadedPropertySources();
}
initializeProfiles() 加载所有可能的profiles
private void initializeProfiles() {
// The default profile for these purposes is represented as null. We add it
// first so that it is processed first and has lowest priority.
this.profiles.add(null);
Set<Profile> activatedViaProperty = getProfilesActivatedViaProperty();
this.profiles.addAll(getOtherActiveProfiles(activatedViaProperty));
// Any pre-existing active profiles set via property sources (e.g.
// System properties) take precedence over those added in config files.
addActiveProfiles(activatedViaProperty);
if (this.profiles.size() == 1) { // only has null profile
for (String defaultProfileName : this.environment.getDefaultProfiles()) {
Profile defaultProfile = new Profile(defaultProfileName, true);
this.profiles.add(defaultProfile);
}
}
}
大概就是,如果没有spring.profiles.active 和 spring.profiles.include都没有特别指定激活的profile的话
没有特别指定profile的话就是:null + default,也就是我们常见的application.properties 和 application-default.properties这种
如果指定了那就是:null + 已经激活(pre-existing)的profile + spring.profiles.active + spring.profiles.include
addLoadedPropertySources() 保证了 application-{profile}里的会覆盖不带profile的配置
private void addLoadedPropertySources() {
MutablePropertySources destination = this.environment.getPropertySources();
List<MutablePropertySources> loaded = new ArrayList<>(this.loaded.values());
//这里顺序颠倒下,保证了优先add的是带profile的,默认的profile是优先级最低的
Collections.reverse(loaded);
String lastAdded = null;
Set<String> added = new HashSet<>();
for (MutablePropertySources sources : loaded) {
for (PropertySource<?> source : sources) {
if (added.add(source.getName())) {
addLoadedPropertySource(destination, lastAdded, source);
lastAdded = source.getName();
}
}
}
}
举个例子,假如激活了多个profile比如:--spring.profiles.active=prd1,prd2,最终优先级上prd1 > prd2 > default(null)
网友评论