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
本文最先公布至微信公众号,版权所有,禁止转载!