大家好,这篇文章将跟大家一起来分析一下SpringBoot启动及配置文件加载原理分析。废话不多说,直接开干吧。。。。。
一、看前必备技能
Spring SPI机制,类似像Java的ServiceLoader、或者Dubbo的ExtensionLoader。
因为下面讲到的Spring的Listener加载机制会涉及到SPI技术(当然这里Spring的监听事件不清楚的小伙伴可以先去做个了解)。
二、SpringBoot初始化启动原理分析
1、由启动主动函数入口切入分析
2、由启动源码分析 SpringApplication.run(DszMasterApplication.class, args);这里面有两个内容,第一初始化SpringApplication,第二是初始化SpringApplication后开始真正运行run方法。
如下图:
3、这里先看SpringApplication的初始化,其实里面最重要的就是SpringBoot自动装载机制,像监听器Listeners初始化,还有什么InitiaLizers。当然还有很多其他初始化任务。这里我们来重点看一下Listener监听注册的初始化。
由上面截图new SpringApplication()构造方法进去可以看到
这里我们重点看下setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));,由getSpringFactoriesInstances进去可以看到
这里的names就是收集了初始化后的ApplicationListener的所有实现的监听器,具体有10个如下图
接下来给大家再往下具体分析这个监听器是如何被初始化的,进入SpringFactoriesLoader.loadFactoryNames(type, classLoader)中如下
然后再进入loadSpringFactories方法,如下
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//这里将会最终存放所有初始化后的监听器
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration<URL> urls = (classLoader != null ?
//下面的的 FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”,这个地方往下就会涉及到Spring的自动装配SPI机制了
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
//这里将会吧所有的初始化的监听对象放入缓存中
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
那么上面的spring.factories文件是在哪里的呢,通过调试得知如下图
由此可知我们可以按照这个path找出这个文件
现在让我们来看下这个文件到底张什么样的,我们打开这个文章一起来看下
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
//以下都是ApplicatinListener的实现类,这些类都将会在上面
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer
# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
由上内容得知,spring.factories定义了一系列springboot启动需要杯加载初始化的类,通过如下调试得知
这里我们来具体看下ApplictionListener加载的那些类,因为这些跟我们接下来要讲的CnfigFileListener会有关系。其实很简单,在MultiValueMap<String, String> result = cache.get(classLoader);的结果集别刻意看出,因为最终初始化的
所有对象都将add到这个result中去。看下结果图如下:
在这里边可以看到所有的Listener初始化的结果。
今晚由于时间比较晚,还有run部分和配置文件加载原理就留给下次给大家补上。由于最近刚写博客,样式排版上没有太多精力,后期会给大家慢慢优化回来。
今晚总结时序图给大家回顾一下吧:
具体细节大家按照上面讲的回顾就好了。