日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > > 架構師社區(qū)
[導讀]不得不說SpringBoot的開發(fā)者是在為大眾程序猿謀福利,把大家都慣成了懶漢,xml不配置了,連tomcat也懶的配置了,典型的一鍵啟動系統(tǒng),那么tomcat在springboot是怎么啟動的呢?



前言


不得不說SpringBoot的開發(fā)者是在為大眾程序猿謀福利,把大家都慣成了懶漢,xml不配置了,連tomcat也懶的配置了,典型的一鍵啟動系統(tǒng),那么tomcat在springboot是怎么啟動的呢?


內(nèi)置tomcat


開發(fā)階段對我們來說使用內(nèi)置的tomcat是非常夠用了,當然也可以使用jetty。


<dependency>
???<groupId>org.springframework.bootgroupId>
???<artifactId>spring-boot-starter-webartifactId>
???<version>2.1.6.RELEASEversion>
dependency>


@SpringBootApplication
public?class?MySpringbootTomcatStarter{
????public?static?void?main(String[] args) {
????????Long time=System.currentTimeMillis();
????????SpringApplication.run(MySpringbootTomcatStarter.class);
????????System.out.println("===應用啟動耗時:"+(System.currentTimeMillis()-time)+"===");
????}
}


這里是main函數(shù)入口,兩句代碼最耀眼,分別是SpringBootApplication注解和SpringApplication.run()方法。


發(fā)布生產(chǎn)


發(fā)布的時候,目前大多數(shù)的做法還是排除內(nèi)置的tomcat,打瓦包(war)然后部署在生產(chǎn)的tomcat中,好吧,那打包的時候應該怎么處理?


<dependency>
????<groupId>org.springframework.bootgroupId>
????<artifactId>spring-boot-starter-webartifactId>
????
????<exclusions>
????????<exclusion>
????????????<groupId>org.springframework.bootgroupId>
????????????<artifactId>spring-boot-starter-tomcatartifactId>
????????exclusion>
????exclusions>
dependency>

<dependency>
????<groupId>javax.servletgroupId>
????<artifactId>javax.servlet-apiartifactId>
????<version>3.1.0version>
????<scope>providedscope>
dependency>


更新main函數(shù),主要是繼承SpringBootServletInitializer,并重寫configure()方法。


@SpringBootApplication
public?class?MySpringbootTomcatStarter?extends?SpringBootServletInitializer?{
????public?static?void?main(String[] args)?{
????????Long time=System.currentTimeMillis();
????????SpringApplication.run(MySpringbootTomcatStarter.class);
????????System.out.println("===應用啟動耗時:"+(System.currentTimeMillis()-time)+"===");
????}

????@Override
????protected?SpringApplicationBuilder configure(SpringApplicationBuilder builder)?{
????????return?builder.sources(this.getClass());
????}
}


從main函數(shù)說起

public?static?ConfigurableApplicationContext run(Class primarySource, String... args) {
????return?run(new?Class[]{primarySource}, args);
}

--這里run方法返回的是ConfigurableApplicationContext
public?static?ConfigurableApplicationContext run(Class[] primarySources, String[] args) {
??return?(new?SpringApplication(primarySources)).run(args);
}


public?ConfigurableApplicationContext run(String... args) {
??ConfigurableApplicationContext context = null;
??Collection 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,這里你可以自己涂鴉一下,換成自己項目的logo
????Banner printedBanner = this.printBanner(environment);
????
????//創(chuàng)建應用上下文
????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);
????
????listeners.started(context);
????this.callRunners(context, applicationArguments);
??} catch?(Throwable var10) {
????
??}

??try?{
????listeners.running(context);
????return?context;
??} catch?(Throwable var9) {
????
??}
}


既然我們想知道tomcat在SpringBoot中是怎么啟動的,那么run方法中,重點關注創(chuàng)建應用上下文(createApplicationContext)和刷新上下文(refreshContext)。


創(chuàng)建上下文


/創(chuàng)建上下文
protected?ConfigurableApplicationContext createApplicationContext() {
??Class contextClass = this.applicationContextClass;
??if?(contextClass == null) {
????try?{
??????switch(this.webApplicationType) {
????????case?SERVLET:
????????????????????//創(chuàng)建AnnotationConfigServletWebServerApplicationContext
????????????contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
??????????break;
????????case?REACTIVE:
??????????contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
??????????break;
????????default:
??????????contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
??????}
????} catch?(ClassNotFoundException var3) {
??????throw?new?IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
????}
??}

??return?(ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}


這里會創(chuàng)建AnnotationConfigServletWebServerApplicationContext類。


而AnnotationConfigServletWebServerApplicationContext類繼承了ServletWebServerApplicationContext,而這個類是最終集成了AbstractApplicationContext。


刷新上下文


//SpringApplication.java
//刷新上下文
private?void?refreshContext(ConfigurableApplicationContext context)?{
??this.refresh(context);
??if?(this.registerShutdownHook) {
????try?{
??????context.registerShutdownHook();
????} catch?(AccessControlException var3) {
????}
??}
}

//這里直接調(diào)用最終父類AbstractApplicationContext.refresh()方法
protected?void?refresh(ApplicationContext applicationContext)?{
??((AbstractApplicationContext)applicationContext).refresh();
}


//AbstractApplicationContext.java
public?void?refresh()?throws?BeansException, IllegalStateException {
??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();
??????//調(diào)用各個子類的onRefresh()方法,也就說這里要回到子類:ServletWebServerApplicationContext,調(diào)用該類的onRefresh()方法
??????this.onRefresh();
??????this.registerListeners();
??????this.finishBeanFactoryInitialization(beanFactory);
??????this.finishRefresh();
????} catch?(BeansException var9) {
??????this.destroyBeans();
??????this.cancelRefresh(var9);
??????throw?var9;
????} finally?{
??????this.resetCommonCaches();
????}

??}
}


//ServletWebServerApplicationContext.java
//在這個方法里看到了熟悉的面孔,this.createWebServer,神秘的面紗就要揭開了。
protected?void?onRefresh()?{
??super.onRefresh();
??try?{
????this.createWebServer();
??} catch?(Throwable var2) {
????
??}
}

//ServletWebServerApplicationContext.java
//這里是創(chuàng)建webServer,但是還沒有啟動tomcat,這里是通過ServletWebServerFactory創(chuàng)建,那么接著看下ServletWebServerFactory
private?void?createWebServer()?{
??WebServer webServer = this.webServer;
??ServletContext servletContext = this.getServletContext();
??if?(webServer == null?&& servletContext == null) {
????ServletWebServerFactory factory = this.getWebServerFactory();
????this.webServer = factory.getWebServer(new?ServletContextInitializer[]{this.getSelfInitializer()});
??} else?if?(servletContext != null) {
????try?{
??????this.getSelfInitializer().onStartup(servletContext);
????} catch?(ServletException var4) {
????
????}
??}

??this.initPropertySources();
}

//接口
public?interface?ServletWebServerFactory?{
????WebServer getWebServer(ServletContextInitializer... initializers);
}

//實現(xiàn)
AbstractServletWebServerFactory
JettyServletWebServerFactory
TomcatServletWebServerFactory
UndertowServletWebServerFactory


這里ServletWebServerFactory接口有4個實現(xiàn)類


SpringBoot內(nèi)置tomcat啟動原理

而其中我們常用的有兩個:TomcatServletWebServerFactory和JettyServletWebServerFactory。


//TomcatServletWebServerFactory.java
//這里我們使用的tomcat,所以我們查看TomcatServletWebServerFactory。到這里總算是看到了tomcat的蹤跡。
@Override
public?WebServer getWebServer(ServletContextInitializer... initializers)?{
??Tomcat tomcat = new?Tomcat();
??File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
??tomcat.setBaseDir(baseDir.getAbsolutePath());
????//創(chuàng)建Connector對象
??Connector connector = new?Connector(this.protocol);
??tomcat.getService().addConnector(connector);
??customizeConnector(connector);
??tomcat.setConnector(connector);
??tomcat.getHost().setAutoDeploy(false);
??configureEngine(tomcat.getEngine());
??for?(Connector additionalConnector : this.additionalTomcatConnectors) {
????tomcat.getService().addConnector(additionalConnector);
??}
??prepareContext(tomcat.getHost(), initializers);
??return?getTomcatWebServer(tomcat);
}

protected?TomcatWebServer getTomcatWebServer(Tomcat tomcat)?{
??return?new?TomcatWebServer(tomcat, getPort() >= 0);
}

//Tomcat.java
//返回Engine容器,看到這里,如果熟悉tomcat源碼的話,對engine不會感到陌生。
public?Engine getEngine()?{
????Service service = getServer().findServices()[0];
????if?(service.getContainer() != null) {
????????return?service.getContainer();
????}
????Engine engine = new?StandardEngine();
????engine.setName( "Tomcat"?);
????engine.setDefaultHost(hostname);
????engine.setRealm(createDefaultRealm());
????service.setContainer(engine);
????return?engine;
}
//Engine是最高級別容器,Host是Engine的子容器,Context是Host的子容器,Wrapper是Context的子容器


getWebServer這個方法創(chuàng)建了Tomcat對象,并且做了兩件重要的事情:把Connector對象添加到tomcat中,configureEngine(tomcat.getEngine());
? ? ? ? ? ?

getWebServer方法返回的是TomcatWebServer。


//TomcatWebServer.java
//這里調(diào)用構造函數(shù)實例化TomcatWebServer
public?TomcatWebServer(Tomcat tomcat, boolean autoStart) {
??Assert.notNull(tomcat, "Tomcat Server must not be null");
??this.tomcat = tomcat;
??this.autoStart = autoStart;
??initialize();
}

private?void?initialize() throws WebServerException {
????//在控制臺會看到這句日志
??logger.info("Tomcat initialized with port(s): "?+ getPortsDescription(false));
??synchronized (this.monitor) {
????try?{
??????addInstanceIdToEngineName();

??????Context context = findContext();
??????context.addLifecycleListener((event) -> {
????????if?(context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
??????????removeServiceConnectors();
????????}
??????});

??????//===啟動tomcat服務===
??????this.tomcat.start();

??????rethrowDeferredStartupExceptions();

??????try?{
????????ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
??????}
??????catch?(NamingException ex) {
????????????????
??????}
????????????
????????????//開啟阻塞非守護進程
??????startDaemonAwaitThread();
????}
????catch?(Exception ex) {
??????stopSilently();
??????destroySilently();
??????throw?new?WebServerException("Unable to start embedded Tomcat", ex);
????}
??}
}


//Tomcat.java
public?void?start()?throws?LifecycleException {
??getServer();
??server.start();
}
//這里server.start又會回到TomcatWebServer的
public?void?stop()?throws?LifecycleException {
??getServer();
??server.stop();
}


//TomcatWebServer.java
//啟動tomcat服務
@Override
public?void?start()?throws?WebServerException {
??synchronized?(this.monitor) {
????if?(this.started) {
??????return;
????}
????try?{
??????addPreviouslyRemovedConnectors();
??????Connector connector = this.tomcat.getConnector();
??????if?(connector != null?&& this.autoStart) {
????????performDeferredLoadOnStartup();
??????}
??????checkThatConnectorsHaveStarted();
??????this.started = true;
??????//在控制臺打印這句日志,如果在yml設置了上下文,這里會打印
??????logger.info("Tomcat started on port(s): "?+ getPortsDescription(true) + " with context path '"
??????????+ getContextPath() + "'");
????}
????catch?(ConnectorStartFailedException ex) {
??????stopSilently();
??????throw?ex;
????}
????catch?(Exception ex) {
??????throw?new?WebServerException("Unable to start embedded Tomcat server", ex);
????}
????finally?{
??????Context context = findContext();
??????ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
????}
??}
}

//關閉tomcat服務
@Override
public?void?stop()?throws?WebServerException {
??synchronized?(this.monitor) {
????boolean?wasStarted = this.started;
????try?{
??????this.started = false;
??????try?{
????????stopTomcat();
????????this.tomcat.destroy();
??????}
??????catch?(LifecycleException ex) {
????????
??????}
????}
????catch?(Exception ex) {
??????throw?new?WebServerException("Unable to stop embedded Tomcat", ex);
????}
????finally?{
??????if?(wasStarted) {
????????containerCounter.decrementAndGet();
??????}
????}
??}
}


附:tomcat頂層結構圖


SpringBoot內(nèi)置tomcat啟動原理

tomcat最頂層容器是Server,代表著整個服務器,一個Server包含多個Service。從上圖可以看除Service主要包括多個Connector和一個Container。Connector用來處理連接相關的事情,并提供Socket到Request和Response相關轉化。Container用于封裝和管理Servlet,以及處理具體的Request請求。那么上文提到的Engine>Host>Context>Wrapper容器又是怎么回事呢?我們來看下圖:



SpringBoot內(nèi)置tomcat啟動原理
? ? ??

綜上所述,一個tomcat只包含一個Server,一個Server可以包含多個Service,一個Service只有一個Container,但有多個Connector,這樣一個服務可以處理多個連接。
? ? ?

多個Connector和一個Container就形成了一個Service,有了Service就可以對外提供服務了,但是Service要提供服務又必須提供一個宿主環(huán)境,那就非Server莫屬了,所以整個tomcat的聲明周期都由Server控制。


總結


SpringBoot的啟動主要是通過實例化SpringApplication來啟動的,啟動過程主要做了以下幾件事情:配置屬性、獲取監(jiān)聽器,發(fā)布應用開始啟動事件初、始化輸入?yún)?shù)、配置環(huán)境,輸出banner、創(chuàng)建上下文、預處理上下文、刷新上下文、再刷新上下文、發(fā)布應用已經(jīng)啟動事件、發(fā)布應用啟動完成事件。在SpringBoot中啟動tomcat的工作在刷新上下這一步。而tomcat的啟動主要是實例化兩個組件:Connector、Container,一個tomcat實例就是一個Server,一個Server包含多個Service,也就是多個應用程序,每個Service包含多個Connector和一個Container,而一個Container下又包含多個子容器。


原文鏈接:https://www.cnblogs.com/sword-successful/p/11383723.html


特別推薦一個分享架構+算法的優(yōu)質內(nèi)容,還沒關注的小伙伴,可以長按關注一下:

SpringBoot內(nèi)置tomcat啟動原理

SpringBoot內(nèi)置tomcat啟動原理

SpringBoot內(nèi)置tomcat啟動原理

長按訂閱更多精彩▼

SpringBoot內(nèi)置tomcat啟動原理

如有收獲,點個在看,誠摯感謝

免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權益,請及時聯(lián)系本站刪除( 郵箱:macysun@21ic.com )。
換一批
延伸閱讀

全球嵌入式技術領域的年度盛會2026嵌入式世界展(Embedded World 2026,簡稱EW26)于3月10日至12日在德國紐倫堡成功舉辦。作為物聯(lián)網(wǎng)和邊緣AI領域的領先企業(yè),Silicon Labs(亦稱“芯科科...

關鍵字: 物聯(lián)網(wǎng) 邊緣AI 嵌入式

3月10日至12日,2026年嵌入式世界展(Embedded World 2026,簡稱EW26)在德國紐倫堡展覽中心成功舉辦。作為領先的邊緣AI與智能音頻等媒體處理技術和芯片解決方案提供商,XMOS以沉浸式演示與技術交...

關鍵字: 邊緣AI 智能音頻 嵌入式

在嵌入式系統(tǒng)開發(fā)中,SoC(System on Chip)的多樣性始終是橫亙在開發(fā)者面前的難題。以某工業(yè)物聯(lián)網(wǎng)網(wǎng)關項目為例,其需同時支持NXP i.MX8M、Rockchip RK3566和Allwinner H616三...

關鍵字: Platform Driver模型 嵌入式

在非易失性存儲器領域,EEPROM(電可擦除可編程只讀存儲器)曾長期占據(jù)主流地位,廣泛應用于各類電子設備的參數(shù)存儲、日志記錄等場景。但隨著工業(yè)控制、汽車電子、醫(yī)療設備等領域對存儲性能提出更高要求,F(xiàn)RAM(鐵電隨機存取存...

關鍵字: 存儲器 可編程 嵌入式

康佳特將aReady.COM擴展至Arm架構模塊,基于恩智浦i.MX 95處理器打造應用就緒的軟硬件構建模塊,集成操作系統(tǒng)、系統(tǒng)整合與IoT連接能力,賦能高價值應用快速落地

關鍵字: 處理器 IoT 嵌入式

3月12日,2026年中國家電及消費電子博覽會(以下簡稱:AWE 2026)在上海盛大開幕。展會現(xiàn)場,場景化、系統(tǒng)化、一體化的家電解決方案成為行業(yè)焦點,消費者對家電的關注也已從基礎的尺寸匹配,延伸至對“空間秩序感”和“視...

關鍵字: 消費電子 蒸烤箱 嵌入式

超高效NPU IP在資源受限設備中推進邊緣AI,因而獲得認可

關鍵字: 人工智能 嵌入式 NPU

上海2026年3月12日 /美通社/ -- 3月12日,2026中國家電及消費電子博覽會(AWE 2026)在上海新國際博覽中心和東方樞紐國際商務合作區(qū)展區(qū)正式啟幕。本屆展會以"AI科技?慧享未來"為...

關鍵字: 西門子 博世 嵌入式 洗碗機

在“AI科技,慧享未來”的時代命題下,人工智能正加速滲透至家庭生活的每一個細節(jié)。2026年中國家電及消費電子博覽會(AWE2026)在上海啟幕,聚焦AI技術如何重塑家電形態(tài)與人居體驗。圍繞“智造不凡 悅享非凡”主題,西門...

關鍵字: 嵌入式 冰箱 AI
關閉