spring加载配置文件是通过listener监视器实现的,在springboot启动时:
SpringApplication.java
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
new FailureAnalyzers(context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
listeners.finished(context, (Throwable)null);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
throw new IllegalStateException(var9);
}
}
SpringApplicationRnListeners.java
public void finished(ConfigurableApplicationContext context, Throwable exception) {
Iterator var3 = this.listeners.iterator();
while(var3.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var3.next();
this.callFinishedListener(listener, context, exception);
}
}
private void callFinishedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context, Throwable exception) {
try {
listener.finished(context, exception);
} catch (Throwable var6) {
if (exception == null) {
ReflectionUtils.rethrowRuntimeException(var6);
}
if (this.log.isDebugEnabled()) {
this.log.error("Error handling failed", var6);
} else {
String message = var6.getMessage();
message = message == null ? "no error message" : message;
this.log.warn("Error handling failed (" + message + ")");
}
}
}
EventPublishingRunListener.java
public void finished(ConfigurableApplicationContext context, Throwable exception) {
SpringApplicationEvent event = this.getFinishedEvent(context, exception);
if (context != null && context.isActive()) {
context.publishEvent(event);
} else {
if (context instanceof AbstractApplicationContext) {
Iterator var4 = ((AbstractApplicationContext)context).getApplicationListeners().iterator();
while(var4.hasNext()) {
ApplicationListener> listener = (ApplicationListener)var4.next();
this.initialMulticaster.addApplicationListener(listener);
}
}
if (event instanceof ApplicationFailedEvent) {
this.initialMulticaster.setErrorHandler(new EventPublishingRunListener.LoggingErrorHandler());
}
this.initialMulticaster.multicastEvent(event);
}
}
在容器启动完成后会广播一个SpringApplicationEvent事件,而SpringApplicationEvent事件是继承自ApplicationEvent时间的,由于ConfigFileApplicationListener监听器实现了SmartApplicationListener接口,而SmartApplicationListener接口继承了ApplicationListener接口,所以能监听到上面广播出来的SpringApplicationEvent事件
ConfigFileApplicationListener.java
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
this.addPropertySources(environment, application.getResourceLoader());
this.configureIgnoreBeanInfo(environment);
this.bindToSpringApplication(environment, application);
}
postProcessEnvironment方法是查找application.yml配置文件的入口方法
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
(new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
}
public void load() {
this.propertiesLoader = new PropertySourcesLoader();
this.activatedProfiles = false;
this.profiles = Collections.asLifoQueue(new LinkedList());
this.processedProfiles = new LinkedList();
Set initialActiveProfiles = this.initializeActiveProfiles();
this.profiles.addAll(this.getUnprocessedActiveProfiles(initialActiveProfiles));
if (this.profiles.isEmpty()) {
String[] var2 = this.environment.getDefaultProfiles();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
String defaultProfileName = var2[var4];
ConfigFileApplicationListener.Profile defaultProfile = new ConfigFileApplicationListener.Profile(defaultProfileName, true);
if (!this.profiles.contains(defaultProfile)) {
this.profiles.add(defaultProfile);
}
}
}
this.profiles.add((Object)null);
ConfigFileApplicationListener.Profile profile;
label41:
for(; !this.profiles.isEmpty(); this.processedProfiles.add(profile)) {
profile = (ConfigFileApplicationListener.Profile)this.profiles.poll();
Iterator var8 = this.getSearchLocations().iterator();
while(true) {
while(true) {
if (!var8.hasNext()) {
continue label41;
}
String location = (String)var8.next();
if (!location.endsWith("/")) {
this.load(location, (String)null, profile);
} else {
Iterator var10 = this.getSearchNames().iterator();
while(var10.hasNext()) {
String name = (String)var10.next();
this.load(location, name, profile);
}
}
}
}
}
this.addConfigurationProperties(this.propertiesLoader.getPropertySources());
}
默认先读取的是location,然后是配置文件的名字“application”,最后才是文件类型“properties”或者“yml”;
localtion有多种,可以自行debug:有file:./和file:./config和classpath等目录;
文件类型默认的有四种:properties、xml、yml、yaml;
最后查找的具体路径:location + name + "-" + profile + "." + ext;
private void load(String location, String name, ConfigFileApplicationListener.Profile profile) {
String group = "profile=" + (profile == null ? "" : profile);
String ext;
if (!StringUtils.hasText(name)) {
this.loadIntoGroup(group, location, profile);
} else {
for(Iterator var5 = this.propertiesLoader.getAllFileExtensions().iterator(); var5.hasNext(); this.loadIntoGroup(group, location + name + "." + ext, profile)) {
ext = (String)var5.next();
if (profile != null) {
this.loadIntoGroup(group, location + name + "-" + profile + "." + ext, (ConfigFileApplicationListener.Profile)null);
Iterator var7 = this.processedProfiles.iterator();
while(var7.hasNext()) {
ConfigFileApplicationListener.Profile processedProfile = (ConfigFileApplicationListener.Profile)var7.next();
if (processedProfile != null) {
this.loadIntoGroup(group, location + name + "-" + processedProfile + "." + ext, profile);
}
}
this.loadIntoGroup(group, location + name + "-" + profile + "." + ext, profile);
}
}
}
}
根据拼出来的路径去查找配置文件,一般配置文件都放在classpath目录下面,当读取到classpath目录下的配置文件的时候,程序去加载配置文件
private PropertySource> loadIntoGroup(String identifier, String location, ConfigFileApplicationListener.Profile profile) {
try {
return this.doLoadIntoGroup(identifier, location, profile);
} catch (Exception var5) {
throw new IllegalStateException("Failed to load property source from location '" + location + "'", var5);
}
}
private PropertySource> doLoadIntoGroup(String identifier, String location, ConfigFileApplicationListener.Profile profile) throws IOException {
Resource resource = this.resourceLoader.getResource(location);
PropertySource> propertySource = null;
StringBuilder msg = new StringBuilder();
if (resource != null && resource.exists()) {
String name = "applicationConfig: [" + location + "]";
String group = "applicationConfig: [" + identifier + "]";
propertySource = this.propertiesLoader.load(resource, group, name, profile == null ? null : profile.getName());
if (propertySource != null) {
msg.append("Loaded ");
this.handleProfileProperties(propertySource);
} else {
msg.append("Skipped (empty) ");
}
} else {
msg.append("Skipped ");
}
msg.append("config file ");
msg.append(this.getResourceDescription(location, resource));
if (profile != null) {
msg.append(" for profile ").append(profile);
}
if (resource != null && resource.exists()) {
this.logger.debug(msg);
} else {
msg.append(" resource not found");
this.logger.trace(msg);
}
return propertySource;
}
当加载配置文件时,程序先会读取配置文件的spring.profiles.active属性,确定加载什么环境的配置文件(我是加载dev的),然后将读取到的配置文件的属性加载到profiles队列中重新加载配置文件,所以任何项目都必须现有一个基础的配置文件,如application.yml
private void handleProfileProperties(PropertySource> propertySource) {
ConfigFileApplicationListener.SpringProfiles springProfiles = this.bindSpringProfiles(propertySource);
this.maybeActivateProfiles(springProfiles.getActiveProfiles());
this.addProfiles(springProfiles.getIncludeProfiles());
}
private ConfigFileApplicationListener.SpringProfiles bindSpringProfiles(PropertySource> propertySource) {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(propertySource);
return this.bindSpringProfiles((PropertySources)propertySources);
}
private ConfigFileApplicationListener.SpringProfiles bindSpringProfiles(PropertySources propertySources) {
ConfigFileApplicationListener.SpringProfiles springProfiles = new ConfigFileApplicationListener.SpringProfiles();
RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles, "spring.profiles");
dataBinder.bind(new PropertySourcesPropertyValues(propertySources, false));
springProfiles.setActive(this.resolvePlaceholders(springProfiles.getActive()));
springProfiles.setInclude(this.resolvePlaceholders(springProfiles.getInclude()));
return springProfiles;
}
然后在这个配置文件里面有一个active属性,程序会先拿到这个属性,放到profiles属性中,重新去加载配置文件如application-dev.yml
private void addProfiles(Set profiles) {
Iterator var2 = profiles.iterator();
while(var2.hasNext()) {
ConfigFileApplicationListener.Profile profile = (ConfigFileApplicationListener.Profile)var2.next();
this.profiles.add(profile);
if (!this.environmentHasActiveProfile(profile.getName())) {
this.prependProfile(this.environment, profile);
}
}
}
转载至链接:https://my.oschina.net/jzgycq/blog/1934692