深入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呢? 因為我們的@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;}由于我們這里專門討論TomCat的啟動,所以我們其他的就不多去研究,直接找到最重要的地方:
第6步:刷新容器 ,這一步是整個SpringBoot非常重要的一步,IOC等等核心都是通過這一步來實現的。
我們進入refreshContext()方法看看:
好,繼續點:
繼續:
發現是一個接口,我們看有那些實現類:
哇,有那么多實現類,到底調用的是哪個呢?
java多態的知識來了
這個時候我們去看看,這個方法是誰調用的?
是一個叫ConfigurableApplicationContext的類調用的,那么繼續去尋找,我們就會發現:
我們要找的實現類是這個!
點進去!
代碼很長,我們直接去到onRefresh() 方法。
點進去:
媽的,繼續找實現類:
找到和web相關的實現類進去一看:
來了來了
就是這個方法:
調用了什么方法????
是不是getWebServer()!!
我們看看ServletWebServerFactory的子類(由于我這里的按理項目有兩個Spring版本,不管它,正常情況下面的實現類,一種只有一個):
其中是不是有TomcatServletWebServerFactory?
而這個TomcatServletWebServerFactory是不是在@EnableAutoConfiguration環節創建好的???
好!!! 現在程序拿到了我們的TomcatServletWebServerFactory,并調用了其中的getWebServer()方法!!!!
好了,最終的決戰來了。
getWebServer()方法到底做了什么??
我們到目前為止還沒看到TomCat啟動的任何蛛絲馬跡,getWebServer()方法是我們最后的救命稻草了。
好!開始:
繼續:
new了一個TomcatWebServer對象(WebServer的子類),我們去看看它的構造方法:
一頓非空判斷加賦值,最后調用到了initialize()方法。 看到這個名字就知道,這是什么?
初始化
Tomcat啟動了。
?
小總結
在 SpringApplication.run()中,刷新容器的時候,程序會去找到在@EnableAutoConfiguration階段創建好的ServletWebServerFactory,它的實現類可能是TomCat可能是Jetty,根據我們項目所引入的依賴自動實例化。
最后由ServletWebServerFactory調用getWebServer()方法啟動web容器。
?
?
?
🍅你的點贊收藏是我分享的動力,謝謝。🍅
總結
以上是生活随笔為你收集整理的深入springboot怎么启动tomcat的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于YOLO目标检测及OpenCV实现的
- 下一篇: 逆天了!看大二学生做的超写实CG卷尾猴!