Tomcat 启动初始化和停止

Tomcat 通过 server.xml 配置文件装配一系列组件,并且为组件设计生命周期接口,在容器启停时,协调控制组件的启动初始化停止。容器通常使用脚本启动,脚本主要是检查 Java 环境、设置 JVM 参数,调用 Bootstrap.start 启动。

Bootstrap 是 Catalina 的引导加载类,它构造了一个 commonLoader 类加载器,加载 ${catalina.base}/lib 目录下的类,目的是与应用程序级的类隔离,接下来详细分析每个过程。

在此之前可先了解一下,官网对启动过程的描述,以及提供的启动UML序列图,Startup.txt&UML,这个图囊括了启动过程中类的调用,但我第一次看这个图,也是一脸懵,以下描述的则是通过 DEBGUG 跟出来的,当回过头再看这个图,确实很有用。

初始化

初始化涉及到 server.xml 的解析,Tomcat 使用 Digester 解析,其工作原理理解了很简单,使用 sax 解析,在元素开始和结束,借助一个 ObjectStack 对象栈和一系列解析规则完成组件的初始化,它主要有三个基本规则:

ObjectCreateRule:根据指定的 ClassName 创建一个实例,元素开始时,压入对象栈,结束时,弹出对象栈

SetPropertiesRule:元素开始时,根据其属性,反射调用栈顶元素对应成员变量的 set 方法

SetNextRule:元素结束时,使用set方法建立栈顶元素(child)和(top-1)元素(parent)的父子(组合)关系

各组件都是使用这三个规则进行配置解析,解析过程不再赘述,(这里) 提供一份源码注释,可加断点跟一下,着重关注栈内对象的入栈和出栈,值得注意的是在 GlobalResourcesLifecycleListener 初始化时会触发加载解析 mbeans-descriptors.xml,这个过程太长,可使用断点跳过。

调用 StandardServer.initialize 开始组件的初始化,触发 INIT_EVENT 事件,详细过程:

初始化 StandardServer:首先触发各 Listener(具体有哪些,可查看xml的配置)的执行,然后初始化内部的 Services;

Service 主要是初始化定义的 Connectors;

初始化 Connector:初始化 Adapter 和 ProtocolHandler,处理器有两种不同实现:

Http11NioProtocol 初始化:NioEndpoint 设置线程池名称、设置ConnectionHandler、设置接收和发送 ByteBuffer 容量;SSL相关实现初始化:

初始化 NioEndpoint:初始化 ServerSocketChannel,设置成阻塞模式,绑定端口;设置 Acceptor、Poller 线程数目;初始化 SSL 信息;初始化 NioSelectorPool;

Http11Protocol 初始化:JIoEndpoint 设置线程池名和ConnectionHandler,初始化 ServerSocketFactory:

初始化 JioEndpoint:设置 Acceptor 线程数;创建 ServerSocket 并绑定端口。

初始化完毕

以上就是在组件在init生命周期事件中完成的设置,注意在 Digester 解析过程中,也完成了一系列的设置。

启动

调用 StandardServer.start 开启组件的启动过程,触发 BEFORE_START_EVENT、START_EVENT、AFTER_START_EVENT 事件:

启动 StandardServer:触发执行各 Listener;启动内部的 Services;

Service 默认没有 Listener,首先启动 Engines 、接着启动 Executors、最后启动 Connectors;

启动 Engine,它调用 super.start() 进行启动或触发以下的动作:

尝试启动 Manager、Cluster、Realm(LockOutRealm);

启动子容器 Hosts;

EngineConfig 监听器的执行 - START_EVENT,STOP_EVENT;

启动后台线程,定期检查会话超时。

启动 Host:设置 ErrorReportValve,并添加到自己的 pipeline 中,触发 ADD_VALVE_EVENT 容器事件,调用 super.start():

启动子容器 Contexts;

启动 pipeline 中实现 Lifecycle 的 Valve。

触发 HostConfig 监听器的执行:

PERIODIC_EVENT:检查所有Web应用程序的状态;

START_EVENT:创建 Context,启动并部署 webapps & conf/Catalina/localhost/*.xml;

STOP_EVENT:取消已部署的所有应用。

启动 Context,部署 Web App

根据 context.xml(或默认的)使用 Digester 创建 StandardContext 对象,添加 ContextConfig 监听器,通过 host.addChild 启动 Context;

初始化用于解析 web.xml 的 Digester,创建设置 WebappLoader 且不使用"标准委托模型";

先解析默认的 conf/web.xml,然后处理 WEB-INF/web.xml,创建 StandardWrapper 封装 Servlet。

启动 Connector,无 Listener,它主要是启动 ProtocolHandler:

Http11NioProtocol - 启动 NioEndpoint - 启动 Poller 线程,启动 Acceptor 线程;

Http11Protocol - 启动 JioEndpoint - 启动 Acceptor 线程。

注册 ShutdownHook,阻塞 main 线程,启动完毕。

接下来就该处理请求了,这部分下一篇会介绍。

停止

当调用 Bootstrap.stop 或接收到 SHUTDOWN 指令或者捕捉到系统关闭信号(如ctrl+c,shutdown,logoff)时,开始调用 Catalina.stop 方法,关闭组件,触发 BEFORE_STOP_EVENT、STOP_EVENT 事件:停止Server、Service,暂停 Connector,停止内部组件,停止 Connector,关闭线程池,打断 awaitThread 即 main 线程,结束。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpspjj.html