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 三部分子节点。下文咱们会别离对这些内容进行介绍。
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
Server 的启动 / 进行
通过上文能够晓得,Server 组件重要的就是管制 Tomcat 容器的启动 / 进行,然而启动进行并不是简略的启动 JVM 敞开 JVM 就能够了,Tomcat 容器启动 / 进行是还必须调用容器内所有组件的生命周期办法,启动时须要所有的组件进行初始化,完结时须要所有的组件进行销毁和资源开释。
JVM 的启动 / 进行
JVM 的启动比较简单,咱们在运行 tomcat 启动脚本的时候,会启动 tomcat 的 Jar 文件,从而启动 JVM。
对于 JVM 的退出则略微简单一些,JVM 退出的形式分为以下三种类型:
- 失常敞开:当最初一个非守护线程完结或者调用了 System.exit 或者通过其余特定平台的办法敞开(发送 SIGINT,SIGTERM 信号等)
- 异样敞开:运行中遇到 RuntimeException 异样等。
- 强制敞开:通过调用 Runtime.halt 办法或者是在操作系统中间接 kill(发送 SIGKILL 信号)掉 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,从而实现容器的优雅敞开。
Tomcat 敞开接口
咱们下面讲了 JVM 退出的状况下 Tomcat 怎么实现优雅的敞开,Tomcat 也能够被动关闭程序,咱们在配置 server.xml 文件的时候,会指定 server 的 port 和 shutdown 指令,在须要敞开 Tomcat 容器的时候,咱们只须要向指定端口发送敞开指令,Tomcat 就会被动退出服务。
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
</Server>
生命周期的管制
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";
Service 服务组件
Server 中 Service 的配置如下所示,Service 组件蕴含两种组件:连接器和 Servlet 容器,其中 servlet 容器只有一个,连接器能够由多个。多个连接器能够使 Tomcat 为多种不同的申请协定提供服务,比方一个解决 HTTP 申请,另外一个解决 HTTPS 申请。
连接器负责将 Socket 申请解析为 Request 和 Response,而 Servlet 容器则负责依据业务逻辑解决申请中的 Request 和 Response,Service 服务组件则负责把二者关联起来。我会在其它文章中具体介绍 Servlet 容器和连接器 Connector。
每个连接器组件 Connector 都能够指定一个 Servlet 容器解决其解析失去的 Request 和 Response,所以 Service 的性能比较简单,就是为 Service 中的每个组件设置 Servlet 容器。
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
Server 的其它配置
全局资源 GlobalNamingResources
提供了容器级别的 JNDI 资源配置。比方上面的默认配置,就提供了 Tomcat 用户数据的 JNDI,存储在 conf/tomcat-users.xml 中。容器资源对容器的依赖性比拟高,当初的应用场景比拟少。
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
监听器 Listener
监听器用来监听容器的特定事件,如容器的启动敞开事件等。如下所示,默认的 server.xml 中蕴含了 5 个监听器,咱们接下来会简略介绍默认监听器的性能。
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
</Server>
- VersionLoggerListener:在容器启动前打印各种版本信息,如 JVM 版本、操作系统版本、tomcat 版本等信息。
- AprLifecycleListener:APR 的生命周期解决,APR(Apache portable Run-time libraries,Apache 可移植运行库)的目标如其名称一样,次要为下层的应用程序提供一个能够逾越多操作系统平台应用的底层反对接口库。
- JreMemoryLeakPreventionListener:用于解决上下文类加载器可能呈现的内存泄露问题,启动 Java 内存主动回收工作,每小时触发 FullGC。
- GlobalResourcesLifecycleListener:Tomcat 启动时实例化 JNDI 资源的 MBean,Tomcat 进行时销毁 MBean.
- ThreadLocalLeakPreventionListener:在 Context 敞开的时候清空线程上下文,避免 ThreadLocal 内存泄露。
我是御狐神,欢送大家关注我的微信公众号:wzm2zsd
本文最先公布至微信公众号,版权所有,禁止转载!