1 概述
1.1 生命周期概述
所有的对象都会经历从创建到消亡的过程。这种例子很多。餐馆老板在每天营业之前,都会提前买菜,切菜(提前炒菜),然后为顾客提供点菜服务,晚上收拾厨房,关门回家。餐馆老板每天的营业过程可以看成是有生命的。起于买菜,止于关门。
Tomcat也有生命,在执行java Bootstrap命令的时候,tomcat类实例被创建,初始化后提供服务;当关闭tomcat服务窗口或者kill掉tomcat进程的时候,tomcat被消亡。
1.2 Tomcat的生命周期
1.2.1 概述
Tomcat中的生命周期接口Lifecycle定义了init\start\stop\destroy方法,分别代表生命周期的不同阶段,个人觉得虽然在接口中没有定义create方法,但是create确是不能不提及的。
下面列出了在tomcat对外提供服务的过程中,涉及到的一些类。这里的类做了一些剪裁,比如:MBean相关的类没有出现在下面的表中。
1.2.2 容器初始类
1.2.2.1 初始类列表
类\接口名(实现类) | 描述 |
Bootstrap | Tomcat启动类 |
Catalina | Tomcat启动类,被Bootstrap调用 |
Server(StandardServer) | Tomcat服务器对象 |
NamingResources | Tomcat用于管理JNDI的内容 |
Service(StandardService) | Tomcat服务器对外提供的服务 |
StandardHost | 接收特定主机的请求 |
ContainerBase | 基础容器类,StandardHost等都继承于他 |
LockOutRealm | |
UserDatabaseRealm | |
AccessLogValve | |
ErrorReportValve | |
StandardHostValve | |
Pipeline(StandardPipeline) | |
Connector | Tomcat服务用于接收访问请求的主要类 |
ProtocolHandler(Http11Protocol) | Tomcat服务用于接收Http请求的处理类 |
JIoEndpoint | 完成具体的接收操作 |
MapperListener | |
这里忽略了一些监听器类,比如:StandardServer的6个监听器类。
1.2.2.2 类设计说明
大部分容器初始类的具体实现都是实现Lifecycle接口。LifecycleBase提供了接口Lifecycle的基本实现,他实现了每一个生命周期接口方法,同时在每个方法中使用“模版模式”,定义了对应方法initInternal\startInternal\stopInternal\destroyInternal,让每一个实现Lifecycle的实现类可以自己做一些具体的事情,看下面的类图可以简单体会到tomcat的类设计:
1.2.3 请求处理类
类\接口名(实现类) | 描述 |
Http11Processor | 处理HTTP请求 |
CoyoteAdapter | Adapter. This represents the entry point in a coyote-based servlet container. |
2 生命周期阶段
2.1 Create
执行java Bootstrap命令的时候,tomcat开始启动。在启动的时候,Bootstrap和Catalina两个类首先被创建实例。随后的类比如StandardServer、StandardService等等,在tomcat读取解析配置文件server.xml的时候创建,在创建StandardServer的过程中,一些相关的类随之创建,比如:StandardServer的属性globalNamingResources。
提到server.xml,不得不提到一点。它是tomcat的一个很重要的配置文件,没有它,tomcat是启动不了的。server.xml承载了tomcat诸多的重要配置信息。比如:
Ø 通过他可以指定容器初始类的属性,比如StandardServer的port属性和SHUTDOWN属性是通过<Server port="8005" shutdown="SHUTDOWN">指定的;
Ø 通过server.xml中标签的嵌套关系,也给出了容器初始类的包含关系;
Ø server.xml这个文件告诉我们StandardServer是tomcat初始化类的根。
代码方面,除去Bootstrap和Catalina这两个类之外,对其他容器初始类的创建操作都在Catalina的load方法中完成,该方法的作用之一就是通过解析server.xml文件来实例化StandardServer等类。示例代码如下:
public class Catalina { public void load() { try { inputSource.setByteStream(inputStream); digester.push(this); digester.parse(inputSource); //这行代码执行完后,容器初始类基本就创建好了。 } catch (Exception e) { log.warn("Catalina.start using " + getConfigFile() + ": ", e); return; } } } |
说明:上面的代码仅仅是示例代码,是不完整的代码。
2.2 Init
tomcat在创建了StandardServer等容器初始类后,紧接着初始化容器。容器初始类的init调用过程可以通过一棵树来展示:
初始化过程中做的事情:
Ø 将初始化对象注册到MBeanServer中,比如:StandardService.init()会调用父类LifecycleMBeanBase的initInternal方法实现MBean的注册,示例代码如下:
public abstract class LifecycleMBeanBase extends LifecycleBase implements MBeanRegistration { protected void initInternal() throws LifecycleException { if (oname == null) { mserver = Registry.getRegistry(null, null).getMBeanServer(); oname = register(this, getObjectNameKeyProperties()); } } } |
Ø 除了注册对象到MBeanServer中,位于树上层的初始化类,还会调用下层初始化类的init方法;
Ø 位于树底层的初始化类,通常还会初始化自身的一些属性,比如:JIOEndpoint的serverSocket就是在初始化的时候被实例化的,该过程通过JIOEndpoint的父类AbstractEndpoint的init方法调用JIOEndpoint重写的bind方法实现,示例代码如下:
public class JIoEndpoint extends AbstractEndpoint { @Override public void bind() throws Exception { // Initialize thread count defaults for acceptor if (acceptorThreadCount == 0) { acceptorThreadCount = 1; } // Initialize maxConnections if (getMaxConnections() == 0) { // User hasn't set a value - use the default setMaxConnections(getMaxThreadsExecutor(true)); } if (serverSocketFactory == null) { if (isSSLEnabled()) { serverSocketFactory = handler.getSslImplementation().getServerSocketFactory(this); } else { serverSocketFactory = new DefaultServerSocketFactory(this); } } if (serverSocket == null) { try { if (getAddress() == null) { serverSocket = serverSocketFactory.createSocket(getPort(), getBacklog()); } else { serverSocket = serverSocketFactory.createSocket(getPort(), getBacklog(), getAddress()); } } catch (BindException orig) { String msg; if (getAddress() == null) msg = orig.getMessage() + " <null>:" + getPort(); else msg = orig.getMessage() + " " + getAddress().toString() + ":" + getPort(); BindException be = new BindException(msg); be.initCause(orig); throw be; } } } } |
2.3 Start
重新审视生命周期的create和init接口,他们在做同一件事情,实例化类对象,区别在于,create阶段实例化的对象大部分是容器初始化类,init方法也会实例化一些类,但是这些类往往作为容器初始类的属性存在。
在看完init方法后,我们可以来研究下start接口的调用树,如下图:
几点说明如下:
Ø 该树最上层的方法调用发生在类Catalina的start方法中,Catalina在执行来了方法load后,调用方法start;
Ø 该树中start方法的调用树有个规律,大部分类的start方法只是为了调用下层类的start方法;
Ø 最终起作用的AbstractEndpoint.start()会启用一个ServerSocket,其作用用来监听浏览器或者其他web客户端发到tomcat的http请求。
至此,tomcat就可以对外提供服务了。
2.4 Stop\Destroy
通过执行java Bootstrap stop命令,可以触发Catalina类的stop方法的调用,Catalina的stop方法依次完成生命周期方法stop和destroy方法的调用。这两个方法的设计意图在于释放资源,比如清空NamingResource中的对象、在start方法中启动的serverSocket。
方法的调用树,跟init和start类似,这里不再赘述。