SpringBoot學習系列-war包在tomcat下啟動原理


springBoot項目 war包啟動原理
參考鏈接:

【spring boot war包啟動原理】 https://www.cnblogs.com/stone-with-big-ears/p/10950581.html
【Tomcat war包加載過程】https://www.jianshu.com/p/6e435a5a4fee

spring boot war啟動是利用Servlet 3.0新增的ServletContainerInitializer接口結合SPI(Service Provider Interface)機制實現的。

springBoot的application.java是應用程序啟動入口,它的父類,org.springframework.boot.web.servlet.support.SpringBootServletInitializer

public abstract class SpringBootServletInitializer implements WebApplicationInitializer

springBoot使用war的啟動方式原理實現:

通過spring-web-xxx.jar包的org.springframework.web.SpringServletContainerInitializer類實現ServletContainerInitializer接口,從而達到無web.xml配置的啟動

主要邏輯

Spring在spring-web-version.jar/META-INF/services/javax.servlet.ServletContainerInitializer文件中,
配置了spring對ServletContainerInitializer接口的實現類org.springframework.web.SpringServletContainerInitializer。

Servlet Container啟動階段掃描jar包中META-INF/services/javax.servlet.ServletContainerInitializer文件,
獲取ServletContainerInitializer實現類並實例化,解析ServletContainerInitializer上@HandlesTypes注解,
查找出@HandlesTypes限定的類型集合,作為ServletContainerInitializer.onStartup方法處理的第一個參數c。

Servlet Container依次調用每個ServletContainerInitializer實例的onStartup。war包啟動的場景中會調用SpringServletContainerInitializer.onStartup方法,
該方法循環調用c集合中每個 WebApplicationInitializer子類(即SpringBootServletInitializer)的onStartup方法。

SpringBootServletInitializer.onStartup方法調用SpringBootServletInitializer.createRootApplicationContext方法,
createRootApplicationContext方法中構建SpringApplication並執行SpringApplication.run方法以啟動整個spring項目。

 

 

tomcat啟動主要的相關類,啟動順序從上到下

BootStrap
  Catalina
    StandardServer
        StandardService
            // 從這里開始就是屬於Container 容器范疇
            StandardEngine
                StandardHost
                    StandardContext
                        StandardWrapper

StandardEngine 表示servlet引擎容器
StandardHost 表示虛擬host容器
StandardContext 表示servlet上下文,一個獨立的web應用程序

從StandardContext開始
因為engine,host,context,StandardWrapper都繼承自ContainerBase類,
ContainerBase extends LifecycleMBeanBase
LifecycleMBeanBase extends LifecycleBase
所以,這些container類都實現了Lifecycle接口的監聽器

在StandardContext中,它的監聽器類是:ContextConfig
解析應用程序的操作都是在監聽器中完成了
ContextConfig.java

    ContextConfig.java
    public void lifecycleEvent(LifecycleEvent event) {
        if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
            configureStart();
        } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
            beforeStart();
        ...
    }

 

ContextConfig.configureStart(){
。。。
 webConfig()
。。。
}

在webConfig()方法
  對應用程序掃描web.xml文件
  處理為其他所有內容之后添加的web片段,因此其他所有內容均具有優先權
  將Servlet標記為可覆蓋,SCI配置可以替換默認配置

webConfig(){
    。。。
    // Parse context level web.xml
    InputSource contextWebXml = getContextWebXmlSource();
    if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {
        ok = false;
    }
    。。。
    

}

 

web配置步驟

         servlet context級別的web.xml解析
            如果沒有找到應用程序的/WEB-INF/web.xml文件,默認會設置標志位ok=true,用來后續的ServletContainerInitializer實現類處理
            
        1.掃描應用程序/WEB-INF/lib路徑下的JAR,未找到/META-INF/web-fragment.xml文件的jar包添加到生成的Map中。
            如果任何應用程序JAR都具有 web-fragment.xml文件,則將在此時進行解析。 web-fragment.xml容器提供的JAR文件將被忽略。
            Servlet3.0 WebFragment掃描
        2.確定web-fragments這些片段的啟動順序
        3.查找所有ServletContainerInitializer實現類,
            處理ServletContainerInitializers的實現類,這也是servlet 3.0新增的特性,
            容器在啟動時使用 JAR 服務 API(JAR Service API) 來發現 ServletContainerInitializer 的實現類,
            並且容器將 WEB-INF/lib 目錄下 JAR 包中的類都交給該類的 onStartup() 方法處理,
            我們通常需要在該實現類上使用 @HandlesTypes 注解來指定希望被處理的類,
            過濾掉不希望給 onStartup() 處理的類。在onStartup方法中可以優先加載這些類,
            或者修改其中的方法等。
            這步主要是把這些類找到放到Set<ServletContainerInitializer> scis中;
        4.將應用中的web.xml與orderedFragments進行合並,合並在WebXml類的merge方法中實現
        5.將應用中的web.xml與全局的web.xml文件(conf/web.xml和web.xml.default)進行合並
        6.用合並好的WebXml來配置Context,這一步在處理servlet時,會為每個servlet創建一個wrapper,
            並調用addChild將每個wrapper作為context子容器,后續分析

 



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM