Tomcat容器的Server模块有管理容器的启动和关闭、管理了容器内的服务组件Service、管理了全局JNDI资源的功能,对Tomcat容器的生命周期管理有重要意义。Tomcat的服务组件则是Tomcat的两个核心组件连接器和servlet容器之间的桥梁。本文会对Tomcat容器的服务器组件Server和服务组件Service进行介绍。
我们知道Tomcat容器启动之后就可以一直保持服务,即使请求出现异常也不会退出,只有在收到特定的容器关闭命令时才会退出。Tomcat容器是怎么实现容器的启动?启动之后是如何保证容器一直保持运行?在收到容器关闭命令的时候怎么优雅关闭的呢?这就是Tomcat容器中的Server的功能了。
每个Tomcat容器都会唯一包含一个Server组件,对应于Tomcat安装文件夹下面的server.xml。下面为Tomcat10安装包中conf/server.xml的默认配置。分析xml可知,server节点有 port和shutdown属性,包含Listener、GlobalNamintResources和Service三部分子节点。下文我们会分别对这些内容进行介绍。
通过上文可以知道,Server组件重要的就是控制Tomcat容器的启动/停止,然而启动停止并不是简单的启动JVM关闭JVM就可以了,Tomcat容器启动/停止是还必须调用容器内所有组件的生命周期方法,启动时需要所有的组件进行初始化,结束时需要所有的组件进行销毁和资源释放。
JVM的启动比较简单,我们在运行tomcat启动脚本的时候,会启动tomcat的Jar文件,从而启动JVM。
关于JVM的退出则稍微复杂一些,JVM退出的方式分为以下三种类型:
对于正常关闭和异常关闭,JVM都有机会执行关闭的Hook方法,对于强制关闭则不一定会执行关闭时的hook方法。所以我们在日常使用中应该尽量避免使用kill -9等方法退出JVM。
JVM注册Shutdown Hook的方法如下所示:
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
//
}
});
Tomcat容器启动的时候会通过Runtime.getRuntime().addShutdownHook(Runnable run)
方法向JVM注册关闭回调方法CatalinaShutdownHook,从而实现容器的优雅关闭。
我们上面讲了JVM退出的情况下Tomcat怎么实现优雅的关闭,Tomcat也可以主动关闭程序,我们在配置server.xml文件的时候,会指定server的port和shutdown指令,在需要关闭Tomcat容器的时候,我们只需要向指定端口发送关闭指令,Tomcat就会主动退出服务。
Tomcat中需要实现声明周期管理的组件都会实现Lifecycle接口。通过上文我们知道Tomcat的启动/停止是由Server控制的,那么Server是如何通知容器内的其它组件(如container、connector)启动/停止相关事件的呢?我们先看看Tomcat的结构图,我们可以看到Tomcat容器的组件之间是一层层包含关系,一个Server包含多个Service,一个Service包含多个Container等等。
Tomcat容器在关闭的时候会通知所有的子组件(service组件)容器关闭事件,service组件再通知它的所有子组件容器关闭事件。事件通过父子关系层层传递到各个组件,从而实现组件之间的生命周期管理。
事实上Tomcat容器的生命周期事件不仅仅包含启动/关闭,而是更详细的划分了启动关闭的各个阶段,分为以下代码示例中的各个事件。
public static final String BEFORE_INIT_EVENT = "before_init";
public static final String AFTER_INIT_EVENT = "after_init";
public static final String START_EVENT = "start";
public static final String BEFORE_START_EVENT = "before_start";
public static final String AFTER_START_EVENT = "after_start";
public static final String STOP_EVENT = "stop";
public static final String BEFORE_STOP_EVENT = "before_stop";
public static final String AFTER_STOP_EVENT = "after_stop";
public static final String AFTER_DESTROY_EVENT = "after_destroy";
public static final String BEFORE_DESTROY_EVENT = "before_destroy";
public static final String PERIODIC_EVENT = "periodic";
public static final String CONFIGURE_START_EVENT = "configure_start";
public static final String CONFIGURE_STOP_EVENT = "configure_stop";
Server中Service的配置如下所示,Service组件包含两种组件:连接器和Servlet容器,其中servlet容器只有一个,连接器可以由多个。多个连接器可以使Tomcat为多种不同的请求协议提供服务,比如一个处理HTTP请求,另外一个处理HTTPS请求。
连接器负责将Socket请求解析为Request和Response,而Servlet容器则负责根据业务逻辑处理请求中的Request和Response,Service服务组件则负责把二者关联起来。我会在其它文章中详细介绍Servlet容器和连接器Connector。
每个连接器组件Connector都可以指定一个Servlet容器处理其解析得到的Request和Response,所以Service的功能比较简单,就是为Service中的每个组件设置Servlet容器。
提供了容器级别的JNDI资源配置。比如下面的默认配置,就提供了Tomcat用户数据的JNDI,存储在conf/tomcat-users.xml中。容器资源对容器的依赖性比较高,现在的使用场景比较少。
监听器用来监听容器的特定事件,如容器的启动关闭事件等。如下所示,默认的server.xml中包含了5个监听器,我们接下来会简单介绍默认监听器的功能。
愿与诸君共进步,大量的面试题及答案还有资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系
可以关注小编+转发文章+私信【架构资料】获取,最后祝大家都能拿到自己心仪的offer