SpringBoot啟動及配置文件加載原理分析


大家好,這篇文章將跟大家一起來分析一下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部分和配置文件加載原理就留給下次給大家補上。由於最近剛寫博客,樣式排版上沒有太多精力,后期會給大家慢慢優化回來。

                           今晚總結時序圖給大家回顧一下吧:

                            

 

                           具體細節大家按照上面講的回顧就好了。

 

                      

                         

 

                           

 

 

 

    

                 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM