从启动类打断点进去:
public class Application{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
进入 SpringApplication.run(Application.class, args):
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
进入:run(new Class[]{primarySource}, args):
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
进入run(args):
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 从这里跟进去
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} 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, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
进入this.prepareEnvironment(listeners, applicationArguments):
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
// 从这里跟进去
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;
}
进入listeners.environmentPrepared((ConfigurableEnvironment)environment):
public void environmentPrepared(ConfigurableEnvironment environment) {
Iterator var2 = this.listeners.iterator();
while(var2.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
// 从这里跟进去
listener.environmentPrepared(environment);
}
}
进入listener.environmentPrepared(environment):
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
进入this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment)):
public void multicastEvent(ApplicationEvent event) {
this.multicastEvent(event, this.resolveDefaultEventType(event));
}
进入this.multicastEvent(event, this.resolveDefaultEventType(event));:
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
Iterator var4 = this.getApplicationListeners(event, type).iterator();
while(var4.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var4.next();
Executor executor = this.getTaskExecutor();
if (executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
进入this.invokeListener(listener, event):
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = this.getErrorHandler();
if (errorHandler != null) {
try {
this.doInvokeListener(listener, event);
} catch (Throwable var5) {
errorHandler.handleError(var5);
}
} else {
this.doInvokeListener(listener, event);
}
}
进入this.doInvokeListener(listener, event):
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
} catch (ClassCastException var6) {
String msg = var6.getMessage();
if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
throw var6;
}
Log logger = LogFactory.getLog(this.getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, var6);
}
}
}
进入listener.onApplicationEvent(event):
(在org.springframework.boot.context.config.ConfigFileApplicationListener中)
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
}
if (event instanceof ApplicationPreparedEvent) {
this.onApplicationPreparedEvent(event);
}
}
进入this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event):
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());
}
}
进入:postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication()):
(这里的postProcessors有多个ConfigurableEnvironment的实现类,我们跟入ConfigFileApplicationListener实现类的处理流程)
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
this.addPropertySources(environment, application.getResourceLoader());
}
进入this.addPropertySources(environment, application.getResourceLoader()):
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
(new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
}
进入load():
public void load() {
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 (profile != null && !profile.isDefaultProfile()) {
this.addProfileToEnvironment(profile.getName());
}
this.load(profile, this::getPositiveProfileFilter, this.addToLoaded(MutablePropertySources::addLast, false));
this.processedProfiles.add(profile);
}
this.resetEnvironmentProfiles(this.processedProfiles);
this.load((ConfigFileApplicationListener.Profile)null, this::getNegativeProfileFilter, this.addToLoaded(MutablePropertySources::addFirst, true));
this.addLoadedPropertySources();
}
进入this.load(profile, this::getPositiveProfileFilter, this.addToLoaded(MutablePropertySources::addLast, false)):
private void load(ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
this.getSearchLocations().forEach((location) -> {
boolean isFolder = location.endsWith("/");
Set<String> names = isFolder ? this.getSearchNames() : ConfigFileApplicationListener.NO_SEARCH_NAMES;
names.forEach((name) -> {
this.load(location, name, profile, filterFactory, consumer);
});
});
}
进入this.load(location, name, profile, filterFactory, consumer):
这里的location目录有四种,我的配置文件放在classpath下:
private void load(String location, String name, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
if (!StringUtils.hasText(name)) {
Iterator var6 = this.propertySourceLoaders.iterator();
while(var6.hasNext()) {
PropertySourceLoader loader = (PropertySourceLoader)var6.next();
if (this.canLoadFileExtension(loader, location)) {
this.load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
return;
}
}
}
Set<String> processed = new HashSet();
Iterator var14 = this.propertySourceLoaders.iterator();
while(var14.hasNext()) {
PropertySourceLoader loaderx = (PropertySourceLoader)var14.next();
String[] var9 = loaderx.getFileExtensions();
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String fileExtension = var9[var11];
if (processed.add(fileExtension)) {
this.loadForFileExtension(loaderx, location + name, "." + fileExtension, profile, filterFactory, consumer);
}
}
}
}
进入this.loadForFileExtension(loaderx, 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()) {
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);
}
进入this.load(loader, prefix + fileExtension, profile, profileFilter, consumer):
private void load(PropertySourceLoader loader, String location, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilter filter, ConfigFileApplicationListener.DocumentConsumer consumer) {
try {
Resource resource = this.resourceLoader.getResource(location);
StringBuilder descriptionxx;
if (resource != null && resource.exists()) {
if (!StringUtils.hasText(StringUtils.getFilenameExtension(resource.getFilename()))) {
if (this.logger.isTraceEnabled()) {
descriptionxx = this.getDescription("Skipped empty config extension ", location, resource, profile);
this.logger.trace(descriptionxx);
}
} else {
String name = "applicationConfig: [" + location + "]";
List<ConfigFileApplicationListener.Document> documents = this.loadDocuments(loader, name, resource);
if (CollectionUtils.isEmpty(documents)) {
if (this.logger.isTraceEnabled()) {
StringBuilder description = this.getDescription("Skipped unloaded config ", location, resource, profile);
this.logger.trace(description);
}
} else {
List<ConfigFileApplicationListener.Document> loaded = new ArrayList();
Iterator var10 = documents.iterator();
while(var10.hasNext()) {
ConfigFileApplicationListener.Document document = (ConfigFileApplicationListener.Document)var10.next();
if (filter.match(document)) {
this.addActiveProfiles(document.getActiveProfiles());
this.addIncludedProfiles(document.getIncludeProfiles());
loaded.add(document);
}
}
Collections.reverse(loaded);
if (!loaded.isEmpty()) {
loaded.forEach((documentx) -> {
consumer.accept(profile, documentx);
});
if (this.logger.isDebugEnabled()) {
StringBuilder descriptionx = this.getDescription("Loaded config file ", location, resource, profile);
this.logger.debug(descriptionx);
}
}
}
}
} else {
if (this.logger.isTraceEnabled()) {
descriptionxx = this.getDescription("Skipped missing config ", location, resource, profile);
this.logger.trace(descriptionxx);
}
}
} catch (Exception var12) {
throw new IllegalStateException("Failed to load property source from location '" + location + "'", var12);
}
}
进入this.loadDocuments(loader, name, resource):
private List<ConfigFileApplicationListener.Document> loadDocuments(PropertySourceLoader loader, String name, Resource resource) throws IOException {
ConfigFileApplicationListener.DocumentsCacheKey cacheKey = new ConfigFileApplicationListener.DocumentsCacheKey(loader, resource);
List<ConfigFileApplicationListener.Document> documents = (List)this.loadDocumentsCache.get(cacheKey);
if (documents == null) {
List<PropertySource<?>> loaded = loader.load(name, resource);
documents = this.asDocuments(loaded);
this.loadDocumentsCache.put(cacheKey, documents);
}
return documents;
}
进入loader.load(name, resource):
(我们用的是properties文件,所以进入PropertiesPropertySourceLoader)
public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
Map<String, ?> properties = this.loadProperties(resource);
return properties.isEmpty() ? Collections.emptyList() : Collections.singletonList(new OriginTrackedMapPropertySource(name, properties));
}
进入this.loadProperties(resource):
private Map<String, ?> loadProperties(Resource resource) throws IOException {
String filename = resource.getFilename();
return (Map)(filename != null && filename.endsWith(".xml") ? PropertiesLoaderUtils.loadProperties(resource) : (new OriginTrackedPropertiesLoader(resource)).load());
}
进入(new OriginTrackedPropertiesLoader(resource)).load()):
public Map<String, OriginTrackedValue> load() throws IOException {
return this.load(true);
}
进入this.load(true):
(ps:终于进入我们要找的地方了)
public Map<String, OriginTrackedValue> load(boolean expandLists) throws IOException {
OriginTrackedPropertiesLoader.CharacterReader reader = new OriginTrackedPropertiesLoader.CharacterReader(this.resource);
Throwable var3 = null;
try {
Map<String, OriginTrackedValue> result = new LinkedHashMap();
StringBuilder buffer = new StringBuilder();
while(reader.read()) {
String key = this.loadKey(buffer, reader).trim();
if (expandLists && key.endsWith("[]")) {
key = key.substring(0, key.length() - 2);
int var19 = 0;
while(true) {
OriginTrackedValue value = this.loadValue(buffer, reader, true);
this.put(result, key + "[" + var19++ + "]", value);
if (!reader.isEndOfLine()) {
reader.read();
}
if (reader.isEndOfLine()) {
break;
}
}
} else {
OriginTrackedValue value = this.loadValue(buffer, reader, false);
this.put(result, key, value);
}
}
LinkedHashMap var18 = result;
return var18;
} catch (Throwable var16) {
var3 = var16;
throw var16;
} finally {
if (reader != null) {
if (var3 != null) {
try {
reader.close();
} catch (Throwable var15) {
var3.addSuppressed(var15);
}
} else {
reader.close();
}
}
}
}
分别看下loadKey和loadValue方法:
loadKey:
private String loadKey(StringBuilder buffer, OriginTrackedPropertiesLoader.CharacterReader reader) throws IOException {
buffer.setLength(0);
boolean previousWhitespace = false;
while(!reader.isEndOfLine()) {
if (reader.isPropertyDelimiter()) {
reader.read();
return buffer.toString();
}
// 从这里的判断逻辑可以发现,配置文件的key不能被空白字符分隔
if (!reader.isWhiteSpace() && previousWhitespace) {
return buffer.toString();
}
previousWhitespace = reader.isWhiteSpace();
buffer.append(reader.getCharacter());
reader.read();
}
return buffer.toString();
}
loadValue:
private OriginTrackedValue loadValue(StringBuilder buffer, OriginTrackedPropertiesLoader.CharacterReader reader, boolean splitLists) throws IOException {
buffer.setLength(0);
// 分隔符(:和=)后面的空白字符全部跳过
while(reader.isWhiteSpace() && !reader.isEndOfLine()) {
reader.read();
}
Location location = reader.getLocation();
while(!reader.isEndOfLine() && (!splitLists || !reader.isListDelimiter())) {
buffer.append(reader.getCharacter());
reader.read();
}
Origin origin = new TextResourceOrigin(this.resource, location);
return OriginTrackedValue.of(buffer.toString(), origin);
}
可以看到,对于key,会去掉前后空格(reader.read()方法,对于开头的空白字符会跳过,所以key左边的空白字符是读出来的时候已经去掉了);对于value,value左边的空白字符会被忽略,但是右边的空白字符会被保留:
配置文件:
读取到的配置:
参考文章: