最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot整個(gè)啟動(dòng)過程的分析

 更新時(shí)間:2019年03月13日 09:37:45   作者:Super_PF  
今天小編就為大家分享一篇關(guān)于SpringBoot整個(gè)啟動(dòng)過程的分析,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧

前言

前一篇分析了SpringBoot如何啟動(dòng)以及內(nèi)置web容器,這篇我們一起看一下SpringBoot的整個(gè)啟動(dòng)過程,廢話不多說,正文開始。

正文

一、SpringBoot的啟動(dòng)類是**application,以注解@SpringBootApplication注明。

@SpringBootApplication
public class CmsApplication {
 public static void main(String[] args) {
  SpringApplication.run(CmsApplication.class, args);
 }
}

SpringBootApplication注解是@Configuration,@EnableAutoConfiguration,@ComponentScan三個(gè)注解的集成,分別表示Springbean的配置bean,開啟自動(dòng)配置spring的上下文,組件掃描的路徑,這也是為什么*application.java需要放在根路徑的原因,這樣@ComponentScan掃描的才是整個(gè)項(xiàng)目。

二、該啟動(dòng)類默認(rèn)只有一個(gè)main方法,調(diào)用的是SpringApplication.run方法,下面我們來看一下SpringApplication這個(gè)類。

public static ConfigurableApplicationContext run(Object source, String... args) {
  return run(new Object[]{source}, args);
 }
...
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
  return (new SpringApplication(sources)).run(args);//sources為具體的CmsApplication.class類
 }
...

抽出其中兩個(gè)直接調(diào)用的run方法,可以看出靜態(tài)方法SpringApplication.run最終創(chuàng)建了一個(gè)SpringApplication,并運(yùn)行其中run方法。

查看起構(gòu)造方法:

public SpringApplication(Object... sources) {
  this.bannerMode = Mode.CONSOLE;
  this.logStartupInfo = true;
  this.addCommandLineProperties = true;
  this.headless = true;
  this.registerShutdownHook = true;
  this.additionalProfiles = new HashSet();
  this.initialize(sources);
 }
...

構(gòu)造方法設(shè)置了基礎(chǔ)值后調(diào)用initialize方法進(jìn)行初始化,如下:

private void initialize(Object[] sources) {
  if (sources != null && sources.length > 0) {
   this.sources.addAll(Arrays.asList(sources));
  }
  this.webEnvironment = this.deduceWebEnvironment();
  this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
  this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
  this.mainApplicationClass = this.deduceMainApplicationClass();
 }
...

初始化方法主要做了幾步:

1.將source放入SpringApplication的sources屬性中管理,sources是一個(gè)LinkedHashSet(),這意味著我們可以同時(shí)創(chuàng)建多個(gè)自定義不重復(fù)的Application,但是目前只有一個(gè)。

2.判斷是否是web程序(javax.servlet.Servletorg.springframework.web.context.ConfigurableWebApplicationContext都必須在類加載器中存在),并設(shè)置到webEnvironment屬性中。

3.從spring.factories中找出ApplicationContextInitializer并設(shè)置到初始化器initializers。

4.從spring.factories中找出ApplicationListener,并實(shí)例化后設(shè)置到SpringApplication的監(jiān)聽器listeners屬性中。這個(gè)過程就是找出所有的應(yīng)用程序事件監(jiān)聽器。

5.找出的main方法的類(這里是CmsApplication),并返回Class對(duì)象。

默認(rèn)情況下,initialize方法從spring.factories文件中找出的key為ApplicationContextInitializer的類有:

  • org.springframework.boot.context.config.DelegatingApplicationContextInitializer
  • org.springframework.boot.context.ContextIdApplicationContextInitializer
  • org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
  • org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
  • org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

key為ApplicationListener的有:

  • org.springframework.boot.context.config.ConfigFileApplicationListener
  • org.springframework.boot.context.config.AnsiOutputApplicationListener
  • org.springframework.boot.logging.LoggingApplicationListener
  • org.springframework.boot.logging.ClasspathLoggingApplicationListener
  • org.springframework.boot.autoconfigure.BackgroundPreinitializer
  • org.springframework.boot.context.config.DelegatingApplicationListener
  • org.springframework.boot.builder.ParentContextCloserApplicationListener
  • org.springframework.boot.context.FileEncodingApplicationListener
  • org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

三、SpringApplication構(gòu)造和初始化完成后,便是運(yùn)行其run方法

public ConfigurableApplicationContext run(String... args) {
  StopWatch stopWatch = new StopWatch();// 構(gòu)造一個(gè)任務(wù)執(zhí)行觀察器
  stopWatch.start();// 開始執(zhí)行,記錄開始時(shí)間
  ConfigurableApplicationContext context = null;
  FailureAnalyzers analyzers = null;
  this.configureHeadlessProperty();
  // 獲取SpringApplicationRunListeners,內(nèi)部只有一個(gè)EventPublishingRunListener
  SpringApplicationRunListeners listeners = this.getRunListeners(args);
  // 封裝成SpringApplicationEvent事件然后廣播出去給SpringApplication中的listeners所監(jiān)聽,啟動(dòng)監(jiān)聽
  listeners.starting();
  try {
   // 構(gòu)造一個(gè)應(yīng)用程序參數(shù)持有類
   ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
   // 加載配置環(huán)境
   ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
   Banner printedBanner = this.printBanner(environment);
   // 創(chuàng)建Spring容器(使用BeanUtils.instantiate)
   context = this.createApplicationContext();
   // 若容器創(chuàng)建失敗,分析輸出失敗原因
   new FailureAnalyzers(context);
   // 設(shè)置容器配置環(huán)境,監(jiān)聽等
   this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
   // 刷新容器
   this.refreshContext(context);
   this.afterRefresh(context, applicationArguments);
   // 廣播出ApplicationReadyEvent事件給相應(yīng)的監(jiān)聽器執(zhí)行
   listeners.finished(context, (Throwable)null);
   stopWatch.stop();// 執(zhí)行結(jié)束,記錄執(zhí)行時(shí)間
   if (this.logStartupInfo) {
    (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
   }
   return context;// 返回Spring容器
  } catch (Throwable var9) {
   this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
   throw new IllegalStateException(var9);
  }
 }

run方法過程分析如上,該方法幾個(gè)關(guān)鍵步驟如下:

1.創(chuàng)建了應(yīng)用的監(jiān)聽器SpringApplicationRunListeners并開始監(jiān)聽

2.加載SpringBoot配置環(huán)境(ConfigurableEnvironment),如果是通過web容器發(fā)布,會(huì)加載StandardEnvironment,其最終也是繼承了ConfigurableEnvironment,類圖如下 

可以看出,*Environment最終都實(shí)現(xiàn)了PropertyResolver接口,我們平時(shí)通過environment對(duì)象獲取配置文件中指定Key對(duì)應(yīng)的value方法時(shí),就是調(diào)用了propertyResolver接口的getProperty方法。

3.配置環(huán)境(Environment)加入到監(jiān)聽器對(duì)象中(SpringApplicationRunListeners)

4.創(chuàng)建Spring容器:ConfigurableApplicationContext(應(yīng)用配置上下文),我們可以看一下創(chuàng)建方法

protected ConfigurableApplicationContext createApplicationContext() {
  Class<?> contextClass = this.applicationContextClass;
  if (contextClass == null) {
   try {
    contextClass = Class.forName(this.webEnvironment ? "org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext" : "org.springframework.context.annotation.AnnotationConfigApplicationContext");
   } catch (ClassNotFoundException var3) {
    throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
   }
  }
  return (ConfigurableApplicationContext)BeanUtils.instantiate(contextClass);
 }

方法會(huì)先獲取顯式設(shè)置的應(yīng)用上下文(applicationContextClass),如果不存在,再加載默認(rèn)的環(huán)境配置(通過是否是web environment判斷),默認(rèn)選擇AnnotationConfigApplicationContext注解上下文(通過掃描所有注解類來加載bean),最后通過BeanUtils實(shí)例化上下文對(duì)象,并返回,ConfigurableApplicationContext類圖如下

主要看其繼承的兩個(gè)方向:

  • LifeCycle:生命周期類,定義了start啟動(dòng)、stop結(jié)束、isRunning是否運(yùn)行中等生命周期空值方法
  • ApplicationContext:應(yīng)用上下文類,其主要繼承了beanFactory(bean的工廠類)。

5.回到run方法內(nèi),設(shè)置容器prepareContext方法,將listeners、environment、applicationArguments、banner等重要組件與上下文對(duì)象關(guān)聯(lián)

6.刷新容器,refresh()方法,初始化方法如下:

public void refresh() throws BeansException, IllegalStateException {
  Object var1 = this.startupShutdownMonitor;
  synchronized(this.startupShutdownMonitor) {
   this.prepareRefresh();
   ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
   this.prepareBeanFactory(beanFactory);
   try {
    this.postProcessBeanFactory(beanFactory);
    this.invokeBeanFactoryPostProcessors(beanFactory);
    this.registerBeanPostProcessors(beanFactory);
    this.initMessageSource();
    this.initApplicationEventMulticaster();
    this.onRefresh();
    this.registerListeners();
    this.finishBeanFactoryInitialization(beanFactory);
    this.finishRefresh();
   } catch (BeansException var9) {
    if (this.logger.isWarnEnabled()) {
     this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
    }
    this.destroyBeans();
    this.cancelRefresh(var9);
    throw var9;
   } finally {
    this.resetCommonCaches();
   }
  }
 }

refresh()方法做了很多核心工作比如BeanFactory的設(shè)置,BeanFactoryPostProcessor接口的執(zhí)行、BeanPostProcessor接口的執(zhí)行、自動(dòng)化配置類的解析、spring.factories的加載、bean的實(shí)例化、條件注解的解析、國(guó)際化的初始化等等。這部分內(nèi)容會(huì)在之后的文章中分析。

7.廣播出ApplicationReadyEvent,執(zhí)行結(jié)束返回ConfigurableApplicationContext。

至此,SpringBoot啟動(dòng)完成,回顧整體流程,Springboot的啟動(dòng),主要?jiǎng)?chuàng)建了配置環(huán)境(environment)、事件監(jiān)聽(listeners)、應(yīng)用上下文(applicationContext),并基于以上條件,在容器中開始實(shí)例化我們需要的Bean。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接

相關(guān)文章

  • SpringCloud?Tencent?全套解決方案源碼分析

    SpringCloud?Tencent?全套解決方案源碼分析

    Spring Cloud Tencent實(shí)現(xiàn)Spring Cloud標(biāo)準(zhǔn)微服務(wù)SPI,開發(fā)者可以基于Spring Cloud Tencent開發(fā)Spring Cloud微服務(wù)架構(gòu)應(yīng)用,Spring Cloud Tencent 的核心依托騰訊開源的一站式服務(wù)發(fā)現(xiàn)與治理平臺(tái) Polarismesh,實(shí)現(xiàn)各種分布式微服務(wù)場(chǎng)景,感興趣的朋友一起看看吧
    2022-07-07
  • java實(shí)現(xiàn)順時(shí)針打印矩陣

    java實(shí)現(xiàn)順時(shí)針打印矩陣

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)順時(shí)針打印矩陣的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • 詳解使用Spring Security OAuth 實(shí)現(xiàn)OAuth 2.0 授權(quán)

    詳解使用Spring Security OAuth 實(shí)現(xiàn)OAuth 2.0 授權(quán)

    本篇文章主要介紹了詳解使用Spring Security OAuth 實(shí)現(xiàn)OAuth 2.0 授權(quán),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • Java字母大小寫轉(zhuǎn)換的方法

    Java字母大小寫轉(zhuǎn)換的方法

    這篇文章主要為大家詳細(xì)介紹了Java字母大小寫轉(zhuǎn)換的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • Spring boot 實(shí)現(xiàn)單個(gè)或批量文件上傳功能

    Spring boot 實(shí)現(xiàn)單個(gè)或批量文件上傳功能

    這篇文章主要介紹了Spring boot 實(shí)現(xiàn)單個(gè)或批量文件上傳功能,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2018-08-08
  • Java實(shí)現(xiàn)二叉樹的深度優(yōu)先遍歷和廣度優(yōu)先遍歷算法示例

    Java實(shí)現(xiàn)二叉樹的深度優(yōu)先遍歷和廣度優(yōu)先遍歷算法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)二叉樹的深度優(yōu)先遍歷和廣度優(yōu)先遍歷算法,結(jié)合實(shí)例形式詳細(xì)分析了二叉樹的定義、深度優(yōu)先遍歷與廣度優(yōu)先遍歷算法原理與相關(guān)操作實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2018-04-04
  • Java使用代碼模擬高并發(fā)操作的示例

    Java使用代碼模擬高并發(fā)操作的示例

    本篇文章主要介紹了Java使用代碼模擬高并發(fā)操作的示例,Java通過代碼模擬高并發(fā)可以以最快的方式發(fā)現(xiàn)我們系統(tǒng)中潛在的線程安全性問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • mybatis查詢實(shí)現(xiàn)返回List<Map>類型數(shù)據(jù)操作

    mybatis查詢實(shí)現(xiàn)返回List<Map>類型數(shù)據(jù)操作

    這篇文章主要介紹了mybatis查詢實(shí)現(xiàn)返回List<Map>類型數(shù)據(jù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • Java this 關(guān)鍵字的使用方法詳解

    Java this 關(guān)鍵字的使用方法詳解

    這篇文章主要介紹了Java this 關(guān)鍵字的使用方法詳解的相關(guān)資料,希望通過本文能幫助到大家,讓大家徹底理解掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-10-10
  • 編譯大型Java項(xiàng)目class沖突導(dǎo)致報(bào)錯(cuò)的解決方案

    編譯大型Java項(xiàng)目class沖突導(dǎo)致報(bào)錯(cuò)的解決方案

    這篇文章給大家盤點(diǎn)編譯大型項(xiàng)目class沖突導(dǎo)致報(bào)錯(cuò)的解決方案,文中通過代碼示例介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-10-10

最新評(píng)論

丹棱县| 察隅县| 冀州市| 宿松县| 壶关县| 巴林左旗| 长兴县| 南召县| 长兴县| 阳春市| 商都县| 衡山县| 遵义市| 荣成市| 蒙山县| 独山县| 大名县| 黑山县| 驻马店市| 巴彦淖尔市| 道真| 运城市| 固阳县| 威宁| 新和县| 宣武区| 察哈| 潢川县| 会昌县| 萝北县| 黔南| 曲靖市| 宿迁市| 灵武市| 马尔康县| 宜都市| 大化| 新宁县| 鄂托克前旗| 岢岚县| 黑河市|