• 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子容器,后续分析


  • 相关阅读:
    Cookie和Session的区别
    CSRF攻击与防御(写得非常好)
    AcWing397 逃不掉的路(边双)
    CF1345D Monopole Magnets(构造)
    AcWing1175 最大半连通子图(tarjan)
    西安邮电大学第五届ACM-ICPC校赛 C题 异或生成树(树形dp)
    AcWing368 银河(差分约束)
    AcWing401 从u到v还是从v到u? (tarjan)
    牛客 位数差(二分)
    AcWing367 学校网络(tarjan)
  • 原文地址:https://www.cnblogs.com/gne-hwz/p/13088185.html
Copyright © 2020-2023  润新知