在Tomcat服务器中启动SpringBoot项目原理(简化版)

摘要:
默认情况下,tomcat服务器将在上下文对象路径Xml文件下加载WEB-INF/WEB,该文件用于初始化上下文。Tomcat开始加载项目,项目初始化过程完成。Tomcat从自上而下的关系开始。标准服务器标准服务标准引擎服务器、服务和引擎。这三个类是固定加载的,并实现了用于触发事件的抽象类LifeCycleBase。容器包含关系继承抽象类ContainerBase,它还继承LifeCycleBaseStandardEngineStandardHostStandardContextStandardWrapper。以上所有类都实现了lifeCycle事件侦听器接口,该接口用于从init()、start()、stop()和destroy()触发这些类在生命周期过程中触发的事件,并相应地处理事件侦听器。
总的来说,tomcat方式启动WAR包项目,
tomcat会查询context上下文中实现ServletContainerInitializer接口的类,然后调用类的onStartup(Set<Class<?>> c, ServletContext ctx)方法
Spring的SpringServletContainerInitializer实现了这个ServletContainerInitializer接口,
会获取WebApplicationInitializer接口的实现类,调用onStartup()方法

SpringBoot的类SpringBootServletInitializer实现了Spring的WebApplicationInitializer扩展接口,
会在onStartup()方法中创建SpringApplication类,并调用SpringApplication.run()来完成启动项目
与我们在开发时调用Application.main()方法启动时一样的原理
首先java web服务器,如tomcat,存在着配置要让服务器加载web项目方式
1、在conf/server.xml文件中配置context,即项目的上下文位置(<service><Host><context>2、放在tomcat安装目录的webapp目录下面。
tomcat服务器默认会加载context对象路径下的WEB-INF/web.xml文件,进行context的初始化

tomcat启动到加载项目及项目初始化完成的流程

Tomcat启动时类从上到下关系

StandardServer
    StandardService
        StandardEngine
server,service,engine这三个是固定加载了,实现了抽象类LifeCycleBase 用于事件触发

子容器container包含关系 继承了抽象类ContainerBase类,其也继承了LifeCycleBase StandardEngine StandardHost StandardContext StandardWrapper

上面的类都实现了lifeCycle事件监听接口,用于触发这些类从init(),start(),stop(),destroy()这些生命周期过程中的触发的事件,给事件监听器做相应处理。

而这个接口的实现类org.apache.catalina.util.LifecycleBase又将这些事件进行了细分,重写了上面的4个接口方法,变成8个触发事件

init()初始化事件==》 (初始化前:LifecycleState.INITIALIZING)和(初始化后:LifecycleState.INITIALIZED)

  重写init方法后变成

            setStateInternal(LifecycleState.INITIALIZING, null, false);
            initInternal(); // 真正的类初始化
            setStateInternal(LifecycleState.INITIALIZED, null, false);

start() 启动事件==》 启动前 和 启动后

  真正的启动 startInternal()

。。。

上面说到了ContainerBase抽象类,其在上面8个事件的基础上,

额外实现了Container容器的事件监听addChild(添加子容器),addValve(添加容器容器关联的Pipeline对象),removeChild,removeValve。

tomcat启动到加载context过程

1、启动
2、Catalina.load()方法
    在这里面parseServerXml(true);方法会动态解析conf/server.xml标签,
    然后将解析生成的StandardServer,Listener事件监听,StandardService,StandardThreadExecutor
    其他的Connector,Engine,Host,Context等节点为其配置的解析规则对象,用于xml配置这些节点时,
    也会将动态创建的对象设置到对应的父节点上。
    具体的解析规则设置查看Catalina.createStartDigester()方法
3、 所有必要类的初始化
    StandardServer.initInternal()
        加载服务器全局jar,调用service.init(),触发事件。。。
    StandardService.initInternal()
        调用engine.init(),executor.init(),connector.init()
    StandardEngine.initInternal()
    
    StandardServer.startInternal()
    StandardService.startInternal()
    StandardEngine.startInternal()
        children.startInternal(),即调用host.start()
    StandardHost.startInternal()
        这里触发的事件监听器里有操作:监听器:(HostConfig implements LifecycleListener)
        会查询<Host>节点的appBase="webapps"扫描该路径下的文件夹:会扫描war包 和 已解压的文件 (扫描项目的WEB-INF/web.xml文件解析生成一个context对象)
        contex描述文件部署:将Server中的context的配置单独拿出生成一个xml文件,Host扫描这些文件的路径由Host的xmlBase属性指定
        从这里就开始的项目的加载

后面的步骤就是

StandardContext.startInternal() 

  触发listener事件监听器,

StandardWrapper.startInternal()

  standardWrapper:这是一个Servlet

我们从上面大体流程可以知道StandardContext的创建是通过Host.start()容器的事件监听器HostConfig.deployApps(name)来操作,

   1、部署war包,
2、部署已解压的的文件夹,
3、部署XML descriptor,conf
/server.xml文件的<Host>节点下的<Context>节点对应的项目 然后使用xml解析器解析生成StandardContext容器(解析xml中配置的context时,context = digest.parse(File) 会自动创建org.apache.catalina.core.StandardContext对象), 然后调用将context添加到host容器中:host.addChild(context); 后面就是调用StandardContext.initInternal() , StandardContext.startInternal()

StandardContext.initInternal() 没有做什么操作,将bena注册到JmxMBeanServer 管理服务中,广播bean创建通知

standarContext.startInternal( ), 

 

j2eeType=WebModule,name=//localhost/Spring_redis_war_exploded,J2EEApplication=none,J2EEServer=none

/org/apache/catalina/util/CharsetMapperDefault.properties


增加事件监听器:LifecycleListener
加载webapp资源
    WebAppLoader 创建WebappClassLoaderBase
    加载/WEB-INF/classes
    加载 /WEB-INF/lib
发送configure_start_event事件,然后会通知ContextConfig调用configureStart()方法
fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
    webConfig(); 扫描web.xml,与全局的规则配置进行合并,
        解析web.xml中配置的listener,servlet,filter创建添加到StandardContext中。
        xml解析规则配置类WebRuleSet.addRuleInstances,
        解析类WebXmlParser
            先后调用addContextParam,addFilter,addFilterMapping,
            addListener,addServlet,setMaxFileSize,setMaxRequestSize,addServletMapping
        
        2、processServletContainerInitializers()查询ServletContainerInitializer实现类
    applicationAnnotationsConfig

 org.apache.catalina.startup.ContextConfig.configureStart() 方法中会触发webConfig()方法

会在这个方法里调用processServletContainerInitializers()方法

这个方法会查找META-INF/services/路径下配置好的实现了ServletContainerInitializer接口的类,

如果ServletContainerInitializer接口实现类有注解@HandlesTypes(xxx.class),也会添加到StandardContext的initializers中

private Map<ServletContainerInitializer,Set<Class<?>>> initializers =
new LinkedHashMap<>();

会在StandardContext.startInternal()方法中会遍历调用initializers的onStarup()方法

// Call ServletContainerInitializers
            for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
                initializers.entrySet()) {
                try {
                    entry.getKey().onStartup(entry.getValue(),
                            getServletContext());
                } catch (ServletException e) {
                    log.error(sm.getString("standardContext.sciFail"), e);
                    ok = false;
                    break;
                }
            }
Spring是基于Servlet容器的java框架

也就是说Spring对请求响应的控制是基于Servlet级别的控制,如JFinal框架是基于Filter级别的控制

spring在web.xml中主要的配置

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:/spring-context*.xml</param-value>
    </context-param>

    <!--Spring MVC Servlet controller控制器配置-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:/spring-mvc*.xml</param-value>
        </init-param>
        <!-- 当load-on-startup的值为1时,表示启动容器时,初始化Servlet  -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <!--servlet容器映射到所有路径-->
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

设置Servlet容器

org.springframework.web.servlet.DispatcherServlet

设置context加载过程中需要用到的ServletContextListener,进行系统资源的初始化

org.springframework.web.context.ContextLoaderListener

免责声明:文章转载自《在Tomcat服务器中启动SpringBoot项目原理(简化版)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ADO.NET访问数据库SqlCommand的ExecuteReader方法一般配合sqldatareader使用docker安装nessus下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Tomcat快速入门

简介 Tomcat 是什么 Tomcat 是由 Apache 开发的一个 Servlet 容器,实现了对 Servlet 和 JSP 的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台、安全域管理和Tomcat阀等。 由于 Tomcat 本身也内含了一个 HTTP 服务器,它也可以被视作一个单独的 Web 服务器。但是,不能将 T...

基于STM32之UART串口通信协议(一)详解

一、前言 1、简介   写的这篇博客,是为了简单讲解一下UART通信协议,以及UART能够实现的一些功能,还有有关使用STM32CubeMX来配置芯片的一些操作,在后面我会以我使用的STM32F429开发板来举例讲解(其他STM32系列芯片大多数都可以按照这些步骤来操作的),如有不足请多多指教。 2、UART简介   嵌入式开发中,UART串口通信协议是我...

Golang 的 go mod 管理包

go 1.14.4 初始化项目 mod管理包   go mod init example    可能会报如下错误:  go mod init: modules disabled by GO111MODULE=off; see 'go help modules'   解决   set GO111MODULE=on //window 得用管理员才能更改  ...

三种方式创建bean对象在springIOC容器中初始化、销毁阶段要调用的自定义方法

1. 使用@Bean注解定义initMethod和destroyMethod 所谓initMethod和destroyMethod,是指在springIOC容器中,对于bean对象执行到初始化阶段和销毁阶段所调用的方法,其并不是初始化方法和销毁方法本身。 对于单例模式,initMethod会在创建容器时,构造方法、属性赋值方法完成之后调用,destroyM...

TensorFlow 编程基础

1、TensorFlow   安装:https://www.cnblogs.com/pam-sh/p/12239387.html      https://www.cnblogs.com/pam-sh/p/12241942.html • 是一个开放源代码软件库,用于进行高性能数值计算• 借助其灵活的架构,用户可以轻松地将计算工作部署到多种平台(CPU、G...

SpringBoot整合Mybatis,TypeAliases配置失败的问题

SpringBoot整合Mybatis,TypeAliases配置失败的问题 问题描述 在应用MyBatis时,使用对象关系映射,将对象和Aliase映射起来。 在Mybatis的文档明确写出,如果你没有明确定义实体类的Aliase,框架会自动将Class Name自动 作为别名。 那么问题来了,当使用java -jar xxx.jar&启动的时候...