Spring Boot内嵌Tomcat原理
文章目錄
- 1 ServletWebServerFactoryConfiguration
- 2 onRefresh啟動web服務(wù)
- 2.1 createWebServer創(chuàng)建web服務(wù)
- 2.1.1 getWebServerFactory獲取web服務(wù)工廠
- 2.1.2 getWebServer獲取web服務(wù)
本次的spring-boot-starter-parent版本為2.3.0。
之前分析了Spring boot的啟動源碼的大概流程,結(jié)尾我們說了一些內(nèi)嵌tomcat原理的原理,現(xiàn)在我們來深入探究一下!
1 ServletWebServerFactoryConfiguration
實(shí)際上,spring boot是指出多種服務(wù)器啟動的,并不只是tomcat,還有jetty等。因此我們可以猜測具體哪種服務(wù)器是可以配置的,而spring boot又是以自動配置聞名,那么這些服務(wù)器肯定與某些自動配置類相關(guān)。
實(shí)際上,spring boot的servlet web服務(wù)器的配置類就是位于spring-boot-autoconfigure.jar下的/META-INF/spring.factories文件中的一個名為ServletWebServerFactoryAutoConfiguration的自動配置類。
在該自動配置類中,會通過@Import想容器中注入四個配置類,我們可以看到,各種容器的web服務(wù)配置,Tomcat、Jetty、Undertow,其中Tomcat對應(yīng)EmbeddedTomcat。
這個EmbeddedTomcat配置類又會向Spring容器注入TomcatServletWebServerFactory,這個類就是Tomcat啟動的關(guān)鍵類,用于創(chuàng)建TomcatWebServer。
另外,ServletWebServerFactoryAutoConfiguration中還會注入一系列的Customizer,用于修改內(nèi)嵌Tomcat的參數(shù)和配置。
2 onRefresh啟動web服務(wù)
那么,這個TomcatServletWebServerFactory是怎么在什么時候被加載到容器中并使用的呢?Tomcat又是什么時候被啟動的呢?
之前的文章就講過,在spring boot容器啟動過程中,在創(chuàng)建容器之后,會執(zhí)行刷新容器的操作,也就是refresh()操作,這個操作實(shí)際上就是spring容器的啟動方法,將會加載bean以及各種配置。該方法是spring項(xiàng)目的核心方法,源碼非常多,我們在之前以及花了大量時間講過了,在此不再贅述,之前的文章鏈接Spring IoC容器初始化源碼。
在refresh()方法中,有一個onRefresh()方法。
這個onRefresh方法默認(rèn)是一個空的實(shí)現(xiàn),這是留給子類容器實(shí)現(xiàn)的擴(kuò)展方法。這個方法是在所有的bean定義被注入到容器中之后調(diào)用的,而在onRefresh方法之后,則會對所有的普通單例bean進(jìn)行實(shí)例化和初始化。
默認(rèn)的web服務(wù)容器是AnnotationConfigServletWebServerApplicationContext,它又繼承了ServletWebServerApplicationContext,該類就對onRefresh方法進(jìn)行了實(shí)現(xiàn),并且Spring boot的web服務(wù)器就是在此啟動的!
/*** ServletWebServerApplicationContext實(shí)現(xiàn)的方法*/ @Override protected void onRefresh(){//調(diào)用父類的邏輯super.onRefresh();try{/** 關(guān)鍵方法,創(chuàng)建webserver*/createWebServer();}catch( Throwable ex ){throw new ApplicationContextException( "Unable to start web server", ex );} }可以看到,內(nèi)部調(diào)用了createWebServer方法創(chuàng)建web服務(wù)器。
2.1 createWebServer創(chuàng)建web服務(wù)
createWebServer方法的代碼如下,它會通過之前配置的ServletWebServerFactory,獲取webServer,即創(chuàng)建web服務(wù)器。
一般我們使用的ServletWebServerFactory就是TomcatServletWebServerFactory,使用的webserver就是TomcatWebServer。
在創(chuàng)建了webserver之后,會想容器注入兩個SmartLifecycle類型的bean實(shí)例,這實(shí)際上是一個擴(kuò)展點(diǎn)的實(shí)例,用于實(shí)現(xiàn)容器回調(diào)。
其中,注冊的WebServerStartStopLifecycle實(shí)例,在ServletWebServerApplicationContext類型的容器啟動完畢后會調(diào)用該實(shí)例的start方法啟動webServer并發(fā)送事件,在ServletWebServerApplicationContext類型的容器銷毀時將會調(diào)用該實(shí)例的stop方法銷毀webServer。
private volatile WebServer webServer;/*** ServletWebServerApplicationContext的方法* <p>* 創(chuàng)建web服務(wù)*/ private void createWebServer(){//獲取WebServer,這里默認(rèn)是空的WebServer webServer = this.webServer;//獲取ServletContext,即servlet上下文,這里默認(rèn)是空的ServletContext servletContext = getServletContext();/** 獲取webServer,初始化web服務(wù)*/if( webServer == null && servletContext == null ){//獲取web服務(wù)工廠,默認(rèn)就是TomcatServletWebServerFactoryServletWebServerFactory factory = getWebServerFactory();/** 通過web服務(wù)工廠獲取web服務(wù),核心代碼* 創(chuàng)建內(nèi)嵌的Tomcat并啟動*/this.webServer = factory.getWebServer( getSelfInitializer() );/** 注冊WebServerGracefulShutdownLifecycle的實(shí)例到容器中* ReactiveWebServerApplicationContext容器啟動完畢后會調(diào)用該實(shí)例的start方法* ReactiveWebServerApplicationContext容器銷毀時將會調(diào)用該實(shí)例的stop方法*/getBeanFactory().registerSingleton( "webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle( this.webServer ) );/** 注冊WebServerStartStopLifecycle的實(shí)例到容器中* ServletWebServerApplicationContext容器啟動完畢后會調(diào)用該實(shí)例的start方法嘗試啟動webServer并發(fā)送事件* ServletWebServerApplicationContext容器銷毀時將會調(diào)用該實(shí)例的stop方法銷毀webServer*/getBeanFactory().registerSingleton( "webServerStartStop", new WebServerStartStopLifecycle( this, this.webServer ) );}else if( servletContext != null ){try{getSelfInitializer().onStartup( servletContext );}catch( ServletException ex ){throw new ApplicationContextException( "Cannot initialize servlet context", ex );}}//初始化ConfigurableWebEnvironment類型的配屬數(shù)據(jù)源initPropertySources(); }2.1.1 getWebServerFactory獲取web服務(wù)工廠
該方法獲取web服務(wù)工廠,工廠用于創(chuàng)建web服務(wù)。
/*** ServletWebServerApplicationContext的方法* <p>* 獲取ServletWebServerFactory,用于初始化webServer* 默認(rèn)返回TomcatServletWebServerFactory*/ protected ServletWebServerFactory getWebServerFactory(){//從容器中搜索ServletWebServerFactory類型的beanName數(shù)組//之前的ServletWebServerFactoryConfiguration配置類就會像容器中//注入ServletWebServerFactory的bean,默認(rèn)就是TomcatServletWebServerFactoryString[] beanNames = getBeanFactory().getBeanNamesForType( ServletWebServerFactory.class );//沒有web服務(wù)工廠if( beanNames.length == 0 ){throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing " + "ServletWebServerFactory bean." );}//有多個web服務(wù)工廠if( beanNames.length > 1 ){throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple " + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames ) );}//從容器中獲取web服務(wù)工廠的實(shí)例return getBeanFactory().getBean( beanNames[ 0 ], ServletWebServerFactory.class ); }2.1.2 getWebServer獲取web服務(wù)
ServletWebServerFactory的方法,用于獲取web服務(wù)。其中TomcatServletWebServerFactory的方法用于創(chuàng)建Tomcat實(shí)例并返回TomcatServer。
該方法中的一些名詞比如baseDir、connector、Service、Host、AutoDeploy 、Engine等等都是Tomcat中的概念,我們之前就介紹過了,在此不再贅述:Tomcat的核心組件以及server.xml配置全解【一萬字】。
在最后的getTomcatWebServer方法中會對Tomcat服務(wù)器進(jìn)行啟動。控制臺會輸出日志:Tomcat initialized with port(s): 8080 (http)。
/*** TomcatServletWebServerFactory的方法* 創(chuàng)建內(nèi)嵌的Tomcat** @param initializers 初始化器* @return Tomcat的web服務(wù)*/ @Override public WebServer getWebServer( ServletContextInitializer... initializers ){if( this.disableMBeanRegistry ){Registry.disableRegistry();}//創(chuàng)建Tomcat實(shí)例Tomcat tomcat = new Tomcat();//設(shè)置Tomcat的基本目錄File baseDir = ( this.baseDirectory != null ) ? this.baseDirectory : createTempDir( "tomcat" );tomcat.setBaseDir( baseDir.getAbsolutePath() );//設(shè)置Connector,用于接受請求發(fā)揮響應(yīng)Connector connector = new Connector( this.protocol );connector.setThrowOnFailure( true );tomcat.getService().addConnector( connector );//自定義連接器customizeConnector( connector );tomcat.setConnector( connector );//是否自動部署tomcat.getHost().setAutoDeploy( false );//設(shè)置EngineconfigureEngine( tomcat.getEngine() );//自己擴(kuò)展的連接器for( Connector additionalConnector : this.additionalTomcatConnectors ){tomcat.getService().addConnector( additionalConnector );}//準(zhǔn)備上下文prepareContext( tomcat.getHost(), initializers );//創(chuàng)建TomcatWebServer,啟動Tomcat,返回TomcatWebServerreturn getTomcatWebServer( tomcat ); }Tomcat啟動后的繼續(xù)執(zhí)行Spring的邏輯,初始化bean實(shí)例等等,Spring容器初始化完畢之后,調(diào)用WebServerStartStopLifecycle的start方法,對TomcatWebServer進(jìn)行啟動,此時控制臺會輸出日志:Tomcat started on port(s): 8080 (http) with context path ‘’。
相關(guān)文章:
如有需要交流,或者文章有誤,請直接留言。另外希望點(diǎn)贊、收藏、關(guān)注,我將不間斷更新各種Java學(xué)習(xí)博客!
總結(jié)
以上是生活随笔為你收集整理的Spring Boot内嵌Tomcat原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MapReduce实现手机上网日志分析(
- 下一篇: 生成GUID唯一值的方法汇总(dotne