日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入springboot怎么启动tomcat

發布時間:2023/12/14 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入springboot怎么启动tomcat 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

深入springboot怎么啟動tomcat

  • @EnableAutoConfiguration做了哪些事
    • 小總結
  • Tomcat何時啟動的呢?
    • 小總結

這是中高級工程師面試中常問的問題。
知道現在有多卷了吧!
我記得我剛找工作那會兒,我只要8000的工資,面試官都要問這個問題。我真TM的醉了!

關于SpringBoot自動配置流程請看:深入Springboot啟動流程+自動配置原理.

如果你對基本的啟動原理有大致的了解,那么可以繼續閱讀此篇文章。否則請先閱讀深入Springboot啟動流程+自動配置原理.。
?

@EnableAutoConfiguration做了哪些事

我們知道,因為@EnableAutoConfiguration注解的存在,SpringBoot項目啟動的時候,會去找到依賴包中META-INF/spring.factories文件,將文件中的自動配置類找出來,加載進內存!

那么和Tomcat相關的配置類,也存在于spring.factories之中:


我們發現這里配置了一個類: ServletWebServerFactoryAutoConfiguration。
這個類是干嘛用的呢?
點進去一看!
不看不知道,一看嚇一尿:

根據上圖的標識我們分三步來解釋:

  • @ConditionalOnWebApplication( type = Type.SERVLET):條件判斷,如果當前的項目的類型為Servlet我才繼續運行當前的ServletWebServerFactoryAutoConfiguration配置類,這里判斷通過。

  • @EnableConfigurationProperties({ServerProperties.class}),這個注解我在深入Springboot啟動流程+自動配置原理.中有解釋。那么呢,這里呢,就是去綁定我們application.properties中關于server的參數!
    例如:

    指定我們服務的端口、地址等。在SpringBoot啟動的時候就會被從application.properties中讀取到當前的ServletWebServerFactoryAutoConfiguration配置類中,進行web服務的初始化!

  • @Import(EmbeddedTomcat.class、 EmbeddedJetty.class): 這是什么? Tomcat?Jetty?并且通過@Import注解注入容器了!聰明的朋友猜到了,Tomcat/Jetty服務就是在這里進行初始化的。

  • 好!由于我們這里研究的是TomCat,我們點進EmbeddedTomcat看看!

    可以看到EmbeddedTomcat是一個由@Configuration修飾的靜態內部配置類,向容器中注入了一個名叫TomcatServletWebServerFactory的對象(重點,后面會用到這個對象)。

    這個時候有同學就有疑問了,在ServletWebServerFactoryAutoConfiguration類中通過@Import導入了三個對象:

  • EmbeddedTomcat
  • EmbeddedJetty
  • EmbeddedUndertow
  • 那這里為什么只加載了EmbeddedTomcat呢? 因為我們的@ConditionalOnClass條件注解,我們的依賴中沒有Jetty和Undertow相關的類,因此EmbeddedJetty和EmbeddedUndertow不會加載。只會加載EmbeddedTomcat!

    所以現在呢,重點來到了TomcatServletWebServerFactory這個對象上,我們進去看看。


    我們發現通過new TomcatServletWebServerFactory(); 創建了一個TomcatServletWebServerFactory對象,然后構造方法設置了一系列參數。這里我們直接跳過,去看這個類中最重要的一個方法:getWebServer()

    這個方法我們后面會做解釋,劃重點!!!!!

    ?

    小總結

    那么@EnableAutoConfiguration對于Tomcat的工作現在就做完了,做了什么事情呢?

    向Spring容器中注入了一個初始化后,名叫TomcatServletWebServerFactory的對象。該對象繼承自ServletWebServerFactory接口(記住)。我們現在可以認為TomCat服務準備好了,等待啟動。那什么時候啟動的呢?

    ?
    ?

    Tomcat何時啟動的呢?

    這個時候就要回到我們的啟動類上了:

    這個SpringApplication.run()方法我們之前一直沒有系統介紹過,這里我簡單介紹一下。
    首先我們點進run方法
    發現首先創建了一個SpringApplication對象。
    然后繼續調用到了一個同名的run方法頭上。
    好!
    重點就是這個run方法了,它做了什么事情呢?

    我這里借鑒一下百度百科上面的解釋:

    public ConfigurableApplicationContext run(String... args) {//記錄程序運行時間StopWatch stopWatch = new StopWatch();stopWatch.start();// ConfigurableApplicationContext Spring 的上下文ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();//【1、獲取并啟動監聽器】SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//【2、構造應用上下文環境】ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);//處理需要忽略的BeanconfigureIgnoreBeanInfo(environment);//打印bannerBanner printedBanner = printBanner(environment);///【3、初始化應用上下文】context = createApplicationContext();//實例化SpringBootExceptionReporter.class,用來支持報告關于啟動的錯誤exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);//【4、刷新應用上下文前的準備階段】prepareContext(context, environment, listeners, applicationArguments, printedBanner);//【5、刷新應用上下文】refreshContext(context);//【6、刷新應用上下文后的擴展接口】afterRefresh(context, applicationArguments);//時間記錄停止stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}//發布容器啟動完成事件listeners.started(context);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;}
  • 獲取并啟動監聽器 通過加載META-INF/spring.factories 完成了 SpringApplicationRunListener實例化工作(告訴相關人員,SpringBoot要啟動了,你們把自己該初始化的初始化了)
  • 構造容器環境,簡而言之就是加載系統變量,環境變量,配置文件
  • 創建容器
  • 實例化SpringBootExceptionReporter.class,用來支持報告關于啟動的錯誤
  • 準備容器
  • 刷新容器 :refreshContext(context)
  • 刷新容器后的擴展接口
  • 由于我們這里專門討論TomCat的啟動,所以我們其他的就不多去研究,直接找到最重要的地方:
    第6步:刷新容器 ,這一步是整個SpringBoot非常重要的一步,IOC等等核心都是通過這一步來實現的。

    我們進入refreshContext()方法看看:

    好,繼續點:

    繼續:

    發現是一個接口,我們看有那些實現類:


    哇,有那么多實現類,到底調用的是哪個呢?
    java多態的知識來了
    這個時候我們去看看,這個方法是誰調用的?

    是一個叫ConfigurableApplicationContext的類調用的,那么繼續去尋找,我們就會發現:

    我們要找的實現類是這個!

    點進去!

    代碼很長,我們直接去到onRefresh() 方法。
    點進去:


    媽的,繼續找實現類:

    找到和web相關的實現類進去一看:

    來了來了
    就是這個方法:

  • 獲取到容器中已經存在的ServletWebServerFactory對象(是不是有點熟悉?回到第一節結尾處去看看!),然后調用了什么方法?
  • 調用了什么方法????

    是不是getWebServer()!!

    我們看看ServletWebServerFactory的子類(由于我這里的按理項目有兩個Spring版本,不管它,正常情況下面的實現類,一種只有一個):
    其中是不是有TomcatServletWebServerFactory?
    而這個TomcatServletWebServerFactory是不是在@EnableAutoConfiguration環節創建好的???

    好!!! 現在程序拿到了我們的TomcatServletWebServerFactory,并調用了其中的getWebServer()方法!!!!

    好了,最終的決戰來了。

    getWebServer()方法到底做了什么??

    我們到目前為止還沒看到TomCat啟動的任何蛛絲馬跡,getWebServer()方法是我們最后的救命稻草了。

    好!開始:

  • 創建了一個Tomcat對象,然后一系列賦值。
  • 調用了一個叫getTomcatWebServer()的方法。最終返回一個WebServer對象
  • 繼續:

    new了一個TomcatWebServer對象(WebServer的子類),我們去看看它的構造方法:

    一頓非空判斷加賦值,最后調用到了initialize()方法。 看到這個名字就知道,這是什么?

    初始化


    Tomcat啟動了。

    ?

    小總結

    在 SpringApplication.run()中,刷新容器的時候,程序會去找到在@EnableAutoConfiguration階段創建好的ServletWebServerFactory,它的實現類可能是TomCat可能是Jetty,根據我們項目所引入的依賴自動實例化。

    最后由ServletWebServerFactory調用getWebServer()方法啟動web容器。

    ?
    ?
    ?

    🍅你的點贊收藏是我分享的動力,謝謝。🍅

    總結

    以上是生活随笔為你收集整理的深入springboot怎么启动tomcat的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。