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子容器,后续分析
出处:https://www.cnblogs.com/gne-hwz/
版权:本文版权归作者和博客园共有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任