Tomcat容器的Server模块具有管理容器的启动和关闭、管理容器中的服务组件Service、管理全局JNDI资源等功能,对于Tomcat容器生命周期管理的意义。Tomcat的服务组件是连接Tomcat的两个核心组件连接器和servlet容器的桥梁。本文将介绍Tomcat容器的服务器组件Server和服务组件Service。服务器组件Server我们知道,Tomcat容器启动后可以维护服务,即使请求异常也不会退出。它只会在收到特定的容器关闭命令时退出。Tomcat容器是如何启动容器的?如何保证容器启动后一直运行?如何在收到容器关闭命令时优雅关闭?这就是Tomcat容器中Server的作用。每个Tomcat容器都会唯一包含一个Server组件,对应Tomcat安装文件夹下的server.xml。以下是Tomcat10安装包中conf/server.xml的默认配置。分析xml可知,server节点有port和shutdown属性,包括Listener、GlobalNamintResources和Service三个子节点。下面我们将分别介绍这些内容。ServerStart/Stop从上面可以看出,Server组件对控制Tomcat容器的启停很重要,但是启停停止并不简单启动JVM和关闭JVM就足够了。要启动/停止Tomcat容器,还必须调用容器中所有组件的生命周期方法。开始时需要初始化所有组件,结束时需要销毁所有组件并释放资源。JVM启动/停止JVM启动相对简单。当我们运行tomcat启动脚本时,我们会启动tomcatJar文件来启动JVM。JVM的退出稍微复杂一些。JVM退出的方式分为以下三种:正常关闭:当最后一个非守护线程结束或调用System.exit或被其他平台特定的方法(发送SIGINT、SIGTERM信号等)关闭时。异常关闭:运行时遇到RuntimeException等强制关闭:通过调用Runtime.halt方法或直接在操作系统中kill(发送SIGKILL信号)来dropJVM进程。对于正常关机和非正常关机,JVM都有机会执行关机的Hook方法。对于强制关机,不一定会执行关闭时的hook方法。所以我们在日常使用中应该尽量避免使用kill-9等方式退出JVM。JVM注册ShutdownHook的方法如下:Runtime.getRuntime().addShutdownHook(newThread(){@Overridepublicvoidrun(){//}});Tomcat容器在启动时会通过Runtime.getRuntime()。addShutdownHook(Runnablerun)方法向JVM注册关闭回调方法CatalinaShutdownHook,从而实现容器的优雅关闭。Tomcat关闭接口我们讲了如何在JVM退出时实现Tomcat的优雅关闭。Tomcat也可以主动关闭程序。当我们配置服务器时,我们只需要向指定端口发送关闭命令,Tomcat就会主动退出服务。生命周期控制Tomcat中需要实现语句周期管理的组件会实现生命周期接口。从上面我们知道Tomcat的启动/停止是由服务器控制的,那么服务器是如何通知容器中的其他组件(如container,connector)启动/停止相关事件的呢?我们先来看一下Tomcat的结构图。我们可以看到,Tomcat容器的组件之间存在一层一层的包容关系。一个Server包含多个Service,一个Service包含多个Container,等等。当Tomcat容器关闭时,它会通知所有子组件(服务组件)容器关闭事件,服务组件将容器关闭事件通知其所有子组件。事件通过父子关系逐层传递给各个组件,实现组件间的生命周期管理。事实上,Tomcat容器的生命周期事件不仅仅包括启动/关闭,而是更详细地划分了启动和关闭的各个阶段,在下面的代码示例中分为各个事件。publicstaticfinalStringBEFORE_INIT_EVENT="before_init";publicstaticfinalStringAFTER_INIT_EVENT="after_init";publicstaticfinalStringSTART_EVENT="开始";publicstaticfinalStringBEFORE_START_EVENT="before_start";publicstaticfinalStringSTOP_EVENT="stop";publicstaticfinalStringBEFORE_STOP_EVENT="before_stop";publicstaticfinalStringAFTER_STOP_EVENT="after_stop";publicstaticfinalStringAFTER_DESTROY_EVENT="after_destroy";publicstaticfinalStringBEFORE_DESTROY_EVENT="before_destroy";publicstaticfinalStringPERIODIC_EVENT="periodic";publicstaticfinalStringCONFIGURE_START_EVENT="configure_start";publicstaticfinalStringCONFIGURE_STOP_EVENT="configure_stop";Service服务组件Server中Service的配置如下,Service组件包含两个组件:connection只有一个servlet容器和多个连接器。多个连接器允许Tomcat服务于多种不同的请求协议,例如一种用于HTTP请求,另一种用于HTTPS请求。连接器负责将Socket请求解析为Request和Response,而Servlet容器负责根据业务逻辑处理请求中的Request和Response,Service服务组件负责将两者关联起来。Servlet容器和Connector我会在其他文章中详细介绍。每个连接器组件Connector都可以指定一个Servlet容器来处理它解析的Request和Response,所以Service的功能比较简单,就是为Service中的每个组件设置一个Servlet容器。其他服务器配置全局资源GlobalNamingResources提供容器级别的JNDI资源配置。例如,下面的默认配置提供了Tomcat用户数据的JNDI,存储在conf/tomcat-users.xml中。容器资源高度依赖容器,现在使用场景比较少。ListenerListener监听器用于监听容器的特定事件,比如容器的启动和关闭事件。如下图,默认的server.xml包含5个监听器,接下来我们简单介绍一下默认监听器的作用。VersionLoggerListener:打印容器启动前的各种版本信息,如JVM版本、操作系统版本、tomcat版本等信息。AprLifecycleListener:APR的生命周期处理,APR(ApacheportableRun-timelibraries,Apacheportableruntimelibrary)的用途与其名称相同,主要是为上层应用提供一个底层支持接口库,可以跨多个运行使用系统平台。JreMemoryLeakPreventionListener:用于处理上下文类加载器中可能存在的内存泄漏,启动Java内存自动回收任务,每小时触发一次FullGC。GlobalResourcesLifecycleListener:Tomcat启动时实例化JNDI资源的MBean,Tomcat停止时销毁该MBean。ThreadLocalLeakPreventionListener:当Context关闭时清除线程上下文,防止ThreadLocal内存泄漏。我是狐神,欢迎大家关注我的微信公众号:wzm2zsd本文首发于微信公众号,版权所有,禁止转载!