在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

SpringBoot的嵌入式Web容器是什么時(shí)候加載的?

jf_ro2CN3Fa ? 來(lái)源:CSDN ? 2023-07-11 10:10 ? 次閱讀

0.前言

背景:最近有位開(kāi)發(fā)同學(xué)說(shuō)面試被問(wèn)到Spring Boot 的啟動(dòng)流程,以及被問(wèn)到Spring Boot 的嵌入式Web容器是什么時(shí)候加載的。如何加載的。是怎么無(wú)縫切換的。

這些問(wèn)題,其實(shí)回答起來(lái)也是比較復(fù)雜的。我們今天就從 SpringApplication.run(EasyPaasAdminApplication.class, args);入口,逐漸向下看下執(zhí)行流程。來(lái)試著回答一下前面這兩個(gè)問(wèn)題。

后面關(guān)于SpringBoot 的web容器可以無(wú)縫隨意切換為jetty,undertow..這個(gè)問(wèn)題的回答涉及到Spring Boot是如何設(shè)計(jì)WebServer的。我們后續(xù)專門(mén)講解一下。

1. 執(zhí)行邏輯梳理

一般我們SpringBoot 應(yīng)用的啟動(dòng)入口都是如下這種固定的寫(xiě)法,

de939068-1f8a-11ee-962d-dac502259ad0.png

也可以是這樣

publicstaticvoidmain(String[]args){
SpringApplicationapplication=newSpringApplication(MyApplication.class);
//...customizeapplicationsettingshere
application.run(args)
}

但總之,都是使用SpringApplication 調(diào)用靜態(tài)方法

此方法的注釋

Static helper that can be used to run a SpringApplication from the specified source using default settings.

publicstaticConfigurableApplicationContextrun(ClassprimarySource,String...args){
returnrun(newClass[]{primarySource},args);
}

跟過(guò)來(lái)就到這,可以看到注釋運(yùn)行Spring應(yīng)用程序,創(chuàng)建并刷新一個(gè)新的ApplicationContext。

dece32cc-1f8a-11ee-962d-dac502259ad0.pngdeedf9ea-1f8a-11ee-962d-dac502259ad0.png

跟代碼到這兒其實(shí)我們對(duì)于SpringBoot 的基本啟動(dòng)流程已經(jīng)知道了。但是要解答什么時(shí)候啟動(dòng)的Tomcat 還需要繼續(xù)分析。

df2549ea-1f8a-11ee-962d-dac502259ad0.png

到這兒我們就可以繼續(xù)下去,發(fā)現(xiàn)Spring Boot 啟動(dòng)WebServer。此處的WebServer我就不展開(kāi)了,可以點(diǎn)擊去就三個(gè)方法start ,stop,getPort??梢钥闯鰜?lái)Spring 在設(shè)計(jì)接口的時(shí)候還是很嚴(yán)謹(jǐn)和精簡(jiǎn)。

我們的核心脈絡(luò)是梳理SpringBoot 啟動(dòng)過(guò)程,并且回答Tomcat 是如何被啟動(dòng)的。

df49063c-1f8a-11ee-962d-dac502259ad0.png

我們可以看到WebServer 的實(shí)現(xiàn)目前內(nèi)置的有5種。其實(shí)Spring Boot 還有一個(gè)特性叫做 自動(dòng)裝配。

這就是為什么5個(gè)實(shí)現(xiàn),我們最后啟動(dòng)的是Tomcat。此處也不做展開(kāi)。后面我專門(mén)搞一個(gè)解析SpringBoot 自動(dòng)裝配的文章。

df7fd20c-1f8a-11ee-962d-dac502259ad0.png

我們看一下內(nèi)部start 的TomcatWebServer的內(nèi)部實(shí)現(xiàn)。了解過(guò)Tomcat 源碼的同學(xué)看到這兒就基本明白了。

dfa25a34-1f8a-11ee-962d-dac502259ad0.png

好源碼跟進(jìn)過(guò)程我們到此結(jié)束,我們整理和總結(jié)一下。

通過(guò)掃一遍源碼我們大概可以總結(jié)出來(lái)如下三個(gè)階段

準(zhǔn)備階段、應(yīng)用上下文創(chuàng)建階段、刷新上下文階段。

準(zhǔn)備階段 :Spring Boot 會(huì)加載應(yīng)用程序的初始設(shè)置,并創(chuàng)建 Spring Boot 上下文。這個(gè)階段的核心源碼是 SpringApplication 類的 run() 方法,它會(huì)調(diào)用 Spring Boot 的各個(gè)初始化器進(jìn)行初始化和準(zhǔn)備工作。

應(yīng)用上下文創(chuàng)建階段 : Spring Boot 會(huì)創(chuàng)建應(yīng)用程序的上下文,包括各種配置信息、Bean 的加載和初始化等。這個(gè)階段的核心源碼是 Spring Boot 自動(dòng)配置機(jī)制,通過(guò)掃描 classpath 中的配置文件,自動(dòng)加載和配置各種組件和 Bean。

刷新上下文階段 :Spring Boot 會(huì)執(zhí)行各種啟動(dòng)任務(wù),包括創(chuàng)建 Web 服務(wù)器、加載應(yīng)用程序的配置、初始化各種組件等。這個(gè)階段的核心源碼是 Spring Boot 的刷新機(jī)制,它會(huì)調(diào)用各種初始化器和監(jiān)聽(tīng)器,執(zhí)行各種啟動(dòng)任務(wù)。其中啟動(dòng)Tomcat 就是在這個(gè)環(huán)節(jié)進(jìn)行。

2. 核心源碼解析

既然上面我們已經(jīng)基本上總結(jié)除了,Spring Boot的啟動(dòng)脈絡(luò)。也梳理出了一些核心源碼。那么我們對(duì)啟動(dòng)過(guò)程的核心源碼解析一下。

2.1. 準(zhǔn)備階段

在準(zhǔn)備階段中,Spring Boot 會(huì)加載應(yīng)用程序的初始設(shè)置,并創(chuàng)建 Spring Boot 上下文。這個(gè)階段的核心源碼是 SpringApplication 類的 run() 方法,它會(huì)調(diào)用 Spring Boot 的各個(gè)初始化器進(jìn)行初始化和準(zhǔn)備工作。

publicConfigurableApplicationContextrun(String...args){
//啟動(dòng)計(jì)時(shí)器
StopWatchstopWatch=newStopWatch();
stopWatch.start();

//定義應(yīng)用程序上下文和異常報(bào)告器列表
ConfigurableApplicationContextcontext=null;
CollectionexceptionReporters=newArrayList<>();

//配置Headless屬性
configureHeadlessProperty();

//獲取SpringBoot啟動(dòng)監(jiān)聽(tīng)器
SpringApplicationRunListenerslisteners=getRunListeners(args);
//執(zhí)行啟動(dòng)監(jiān)聽(tīng)器的starting方法
listeners.starting();

try{
//解析命令行參數(shù)
ApplicationArgumentsapplicationArguments=newDefaultApplicationArguments(args);
//準(zhǔn)備應(yīng)用程序環(huán)境
ConfigurableEnvironmentenvironment=prepareEnvironment(listeners,applicationArguments);
//配置忽略BeanInfo
configureIgnoreBeanInfo(environment);
//打印Banner
BannerprintedBanner=printBanner(environment);
//創(chuàng)建應(yīng)用程序上下文
context=createApplicationContext();
//獲取異常報(bào)告器,關(guān)于異常報(bào)告,我下次專門(mén)講一下SpringBoot 的異常收集器。
exceptionReporters=getSpringFactoriesInstances(SpringBootExceptionReporter.class,newClass[]{ConfigurableApplicationContext.class},context);
//準(zhǔn)備應(yīng)用程序上下文
prepareContext(context,environment,listeners,applicationArguments,printedBanner);
//刷新應(yīng)用程序上下文
refreshContext(context);
//刷新后操作
afterRefresh(context,applicationArguments);
//停止計(jì)時(shí)器
stopWatch.stop();
//記錄啟動(dòng)日志
if(this.logStartupInfo){
newStartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(),stopWatch);
}
//執(zhí)行啟動(dòng)監(jiān)聽(tīng)器的started方法
listeners.started(context);
//執(zhí)行Runner
callRunners(context,applicationArguments);
}catch(Throwableex){
//處理啟動(dòng)失敗
handleRunFailure(context,ex,exceptionReporters,listeners);
thrownewIllegalStateException(ex);
}

try{
//執(zhí)行啟動(dòng)監(jiān)聽(tīng)器的running方法
listeners.running(context);
}catch(Throwableex){
//處理啟動(dòng)失敗
handleRunFailure(context,ex,exceptionReporters,null);
thrownewIllegalStateException(ex);
}

//返回應(yīng)用程序上下文
returncontext;
}

在 run() 方法中,Spring Boot 首先會(huì)創(chuàng)建一個(gè) StopWatch 對(duì)象,用于記錄整個(gè)啟動(dòng)過(guò)程的耗時(shí)。然后,Spring Boot 會(huì)調(diào)用 getRunListeners(args) 方法獲取 Spring Boot 的各個(gè)啟動(dòng)監(jiān)聽(tīng)器,并調(diào)用starting() 方法通知這些監(jiān)聽(tīng)器啟動(dòng)過(guò)程已經(jīng)開(kāi)始。接著調(diào)用 prepareEnvironment(listeners, applicationArguments) 方法創(chuàng)建應(yīng)用程序的環(huán)境變量。

這個(gè)方法會(huì)根據(jù)用戶的配置和默認(rèn)設(shè)置創(chuàng)建一個(gè) ConfigurableEnvironment對(duì)象,并將其傳給后面的 createApplicationContext() 方法。printBanner(environment) 方法打印啟動(dòng)界面的 Banner,調(diào)用 refreshContext(context)方法刷新上下文。這個(gè)方法會(huì)啟動(dòng)上下文,執(zhí)行各種啟動(dòng)任務(wù),包括創(chuàng)建 Web 服務(wù)器、加載應(yīng)用程序的配置、初始化各種組件等。具體的啟動(dòng)任務(wù)會(huì)在刷新上下文階段中進(jìn)行。

2.2. 應(yīng)用上下文創(chuàng)建階段

在應(yīng)用上下文創(chuàng)建階段中,Spring Boot 會(huì)創(chuàng)建應(yīng)用程序的上下文,包括各種配置信息、Bean 的加載和初始化等。這個(gè)階段的核心源碼是 Spring Boot 自動(dòng)配置機(jī)制,通過(guò)掃描 classpath 中的配置文件,自動(dòng)加載和配置各種組件和 Bean。

protectedConfigurableApplicationContextcreateApplicationContext(){
ClasscontextClass=this.applicationContextClass;
if(contextClass==null){
try{
switch(this.webApplicationType){
caseSERVLET:
contextClass=Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
caseREACTIVE:
contextClass=Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass=Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch(ClassNotFoundExceptionex){
thrownewIllegalStateException(
"UnabletocreateadefaultApplicationContext,"+
"pleasespecifyanApplicationContextClass",ex);
}
}
return(ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}

在 createApplicationContext() 方法中,Spring Boot 首先會(huì)判斷應(yīng)用程序的類型,如果是 Web 應(yīng)用程序,則會(huì)創(chuàng)建一個(gè) WebApplicationContext;否則,會(huì)創(chuàng)建一個(gè)普通的 ApplicationContext。調(diào)用 BeanUtils.instantiateClass(contextClass) 方法創(chuàng)建應(yīng)用程序的上下文。這個(gè)方法會(huì)根據(jù)上面的邏輯創(chuàng)建一個(gè)相應(yīng)的 ApplicationContext。調(diào)用 load() 方法加載應(yīng)用程序的配置。

這個(gè)方法會(huì)掃描 classpath 中的各種配置文件,例如 application.properties、application.yml、META-INF/spring.factories 等,自動(dòng)配置各種組件和 Bean。調(diào)用 postProcessApplicationContext() 方法對(duì)應(yīng)用程序的上下文進(jìn)行后處理。這個(gè)方法會(huì)調(diào)用各種初始化器和監(jiān)聽(tīng)器,執(zhí)行各種初始化任務(wù)。

2.3. 刷新上下文階段

在刷新上下文階段中,Spring Boot 會(huì)執(zhí)行各種啟動(dòng)任務(wù),包括創(chuàng)建 Web 服務(wù)器(剛才我們跟源碼的時(shí)候也看到了,如上我的截圖)、加載應(yīng)用程序的配置、初始化各種組件等。這個(gè)階段的核心源碼是 Spring Boot 的刷新機(jī)制,它會(huì)調(diào)用各種初始化器和監(jiān)聽(tīng)器,執(zhí)行各種啟動(dòng)任務(wù)。

protectedvoidrefreshContext(ConfigurableApplicationContextapplicationContext){
refresh(applicationContext);
if(this.registerShutdownHook){
try{
applicationContext.registerShutdownHook();
}
catch(AccessControlExceptionex){
//Notallowedinsomeenvironments.
}
}
}

在 refreshContext() 方法中調(diào)用 refresh(applicationContext) 方法刷新上下文。這個(gè)方法是 ApplicationContext 接口的核心方法,會(huì)啟動(dòng)上下文,執(zhí)行各種啟動(dòng)任務(wù)。調(diào)用 registerShutdownHook() 方法注冊(cè)應(yīng)用程序的關(guān)閉鉤子。這個(gè)方法會(huì)在應(yīng)用程序關(guān)閉時(shí)自動(dòng)執(zhí)行,清理資源、關(guān)閉線程等,所以我們利用此特性在服務(wù)關(guān)閉的時(shí)候清理一些資源。并向外部發(fā)送告警通知。

在 refresh(applicationContext) 方法中,Spring Boot 會(huì)執(zhí)行上下文的各種啟動(dòng)任務(wù),包括創(chuàng)建 Web 服務(wù)器、加載應(yīng)用程序的配置、初始化各種組件等。具體的啟動(dòng)任務(wù)會(huì)調(diào)用各種初始化器和監(jiān)聽(tīng)器,例如:

for(ApplicationContextInitializerinitializer:getInitializers()){
initializer.initialize(applicationContext);
}

另外,Spring Boot 還會(huì)調(diào)用各種監(jiān)聽(tīng)器,我們不做贅述,例如:

for(ApplicationListenerlistener:getApplicationListeners()){
if(listenerinstanceofSmartApplicationListener){
SmartApplicationListenersmartListener=(SmartApplicationListener)listener;
if(smartListener.supportsEventType(eventType)
&&smartListener.supportsSourceType(sourceType)){
invokeListener(smartListener,event);
}
}
elseif(supportsEvent(listener,eventType)){
invokeListener(listener,event);
}
}

基本上就是這些了。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5094

    文章

    19183

    瀏覽量

    307753
  • Web服務(wù)器
    +關(guān)注

    關(guān)注

    0

    文章

    138

    瀏覽量

    24488
  • tomcat
    +關(guān)注

    關(guān)注

    0

    文章

    30

    瀏覽量

    4871
  • SpringBoot
    +關(guān)注

    關(guān)注

    0

    文章

    174

    瀏覽量

    201

原文標(biāo)題:三分鐘了解 SpringBoot 的啟動(dòng)流程

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    SpringBoot嵌入式Web容器有哪幾種呢

    種類1.servlett web容器,2.reactive web容器spring-boot支持使用jetty、netty、tomcat、undertow作為
    發(fā)表于 12-16 06:51

    談一談Spring Boot嵌入式Web容器

    Spring Boot嵌入式Web容器Embedded Tomcatorg.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerorg.
    發(fā)表于 12-16 08:16

    Spring Boot嵌入式Web容器原理是什么

    Spring Boot嵌入式Web容器原理Spring Boot的目標(biāo)是構(gòu)建“非常容易創(chuàng)建、獨(dú)立、產(chǎn)品級(jí)別的基于Spring的應(yīng)用”。這些應(yīng)用是“立即可運(yùn)行的”。在這個(gè)過(guò)程中,完全沒(méi)有代碼生成
    發(fā)表于 12-16 07:57

    SpringBoot嵌入式Servlet容器啟動(dòng)原理是什么

    SpringBoot嵌入式Servlet容器啟動(dòng)原理思維導(dǎo)圖
    發(fā)表于 12-20 07:26

    嵌入式Servlet容器啟動(dòng)原理是什么

    一、SpringBoot應(yīng)用啟動(dòng)運(yùn)行run方法二、run方法調(diào)用了refreshContext(context);SpringBoot刷新IOC容器【創(chuàng)建IOC容器對(duì)象,并初始化
    發(fā)表于 12-20 07:54

    SpringBoot應(yīng)用啟動(dòng)運(yùn)行run方法

    什么時(shí)候創(chuàng)建嵌入式的Servlet容器工廠?什么時(shí)候獲取嵌入式的Servlet容器并啟動(dòng)Tomc
    發(fā)表于 12-20 06:16

    嵌入式Servlet容器自動(dòng)配置原理是什么

    這一節(jié)課我們來(lái)說(shuō)一說(shuō)嵌入式Servlet容器自動(dòng)配置原理前面我們都知道怎么去配置容器參數(shù),切換容器,但是我們不知道springboot自動(dòng)配
    發(fā)表于 12-20 06:29

    如何配置嵌入式的Servlet容器

    以前的web應(yīng)用開(kāi)發(fā)我們采取的方式是項(xiàng)目完成后打包成war包,然后配置tomcat啟動(dòng)運(yùn)行項(xiàng)目,而Spring Boot默認(rèn)使用的是嵌入式的tomcat,那我們需要如何配置嵌入式的Servlet
    發(fā)表于 12-20 07:18

    SpringBoot配置嵌入式Servlet

    SpringBoot配置嵌入式Servlet容器定制和修改Servlet容器相關(guān)配置全局配置文件編寫(xiě)WebServerFactoryCustomizer注冊(cè)Servlet三大組件注冊(cè)S
    發(fā)表于 12-20 06:19

    什么時(shí)候獲取嵌入式的Servlet容器并啟動(dòng)Tomcat

    什么時(shí)候創(chuàng)建嵌入式的Servlet容器工廠?什么時(shí)候獲取嵌入式的Servlet容器并啟動(dòng)Tomc
    發(fā)表于 12-20 06:11

    如何對(duì)嵌入式Servlet容器進(jìn)行配置呢

    一、配置嵌入式Servlet容器SpringBoot默認(rèn)使用Tomcat作為嵌入式的Servlet容器;1、定制和修改Servlet
    發(fā)表于 12-21 06:09

    嵌入式Servlet容器啟動(dòng)原理

    SpringBoot源碼學(xué)習(xí)系列之嵌入式Servlet容器啟動(dòng)原理SpringBoot的自動(dòng)配置就是SpringBoot的精髓所在,對(duì)于
    發(fā)表于 12-22 07:23

    如何配置嵌入式Servlet容器

    springboot默認(rèn)使用的是嵌入式的servlet容器(tomcat):定制和修改servlet容器的相關(guān)配置1)修改和server有關(guān)的配置(ServerProperties類
    發(fā)表于 12-24 06:56

    嵌入式引導(dǎo)加載技術(shù)

    嵌入式引導(dǎo)加載技術(shù)
    發(fā)表于 02-08 01:37 ?10次下載

    嵌入式Servlet容器

    配置嵌入式Servlet容器##Spring Boot里面內(nèi)置了嵌入式的Servlet容器(tomcat)點(diǎn)擊pom.xml->右鍵->Diagrams->show
    發(fā)表于 10-20 17:51 ?3次下載
    <b class='flag-5'>嵌入式</b>Servlet<b class='flag-5'>容器</b>
    主站蜘蛛池模板: 久久久久久久性潮 | 婷婷色香五月激情综合2020 | 可以免费看黄的网站 | 萝l在线精品社区资源 | 亚洲一区日韩一区欧美一区a | 国产精品欧美一区二区三区 | 韩日一级毛片 | 夜夜夜夜操 | 奇米影视四色首页手机在线 | 精品国产自在现线看久久 | 国产精品vv在线 | 欧美在线观看一区二区三 | 亚洲精品日韩专区silk | 全部在线播放免费毛片 | www在线视频观看 | 国内视频一区 | 天天干夜夜夜操 | 午夜免费网址 | 男人边吃奶边做视频免费网站 | 理论在线看 | 亚洲天堂bt| 看天堂 | 中文天堂最新版www官网在线 | 人人狠狠综合88综合久久 | h视频在线观看网站 | 国语自产免费精品视频一区二区 | 尻老逼 | 18满xo影院视频免费体验区 | 欧洲天堂网 | 性欧洲女人18 | aaa成人| 超级极品白嫩美女在线 | 日日干夜夜骑 | 四虎国产精品永久在线 | 99久久免费精品国产免费高清 | 色拍视频 | 午夜一级毛片免费视频 | 日本片巨大的乳456线观看 | 欧美三级黄视频 | 一级片免费观看视频 | 视频免费黄色 |