Tomcat是如何启动及运行—对tomcat的源码解析

Posted ningdunquan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tomcat是如何启动及运行—对tomcat的源码解析相关的知识,希望对你有一定的参考价值。

本文是我阅读了Tomcat源码后的一些心得。主要是讲解Tomcat的系统框架,启动流程已经运行过程。若有错漏之处,敬请批评指教。

     先给出几个问题:

tomcat作为一个应用服务器的程序入口在哪里?

tomcat的整体组件结构是什么样的?

tomcat是什么时候及如何创建线程来处理请求的?

tomcat的配置文件context.xml,server.xml,tomcat-users.xml,web.xml什么时候加载的及作用是什么?

最后,tomcat是如何启动运行的?

我通过源码来分析这些问题。

       tomcat作为最常见的应用服务器,对ServerSocketSocket封装使用TCP链接达到通信的目的,我从它的程序入口开始跟踪代码,看它是如何启动的。

     Tomcat组件有ServerServiceContainerConnectorEngineHostContextProtocolHandlerEndPoint

Server一个Server元素代表一整个CatalinaServlet容器,也就是说Server是最顶级的容器,它包含一个或多个Service,这个在后面我们可以看到;

Service由一个或者多个Connector组成,以及一个Engine,负责处理所有Connector所获得的客户请求;

Connector连接器,一个Connector将在某个指定端口上侦听客户请求,并将获得的请求交给Engine来处理,从Engine处获得回应并返回客户;

EngineEngine获得一个请求时,它把该请求匹配到某个Host上,然后把该请求交给该Host来处理;

HostHost获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理;

Context一个Context对应于一个WebApplication,一个WebApplication由一个或者多个Servlet组成(这个就是我们熟悉的上下文对象了);

ContainerEngineHostContext的父类或父接口,这里使用了Composite组合模式,调用它们的start()方法时都会调用父类的此方法;

ProtocolHandler协议处理器,连接器持有用来控制网络端口监听组件运行;

EndPoint负责监控网络端口的组件,启动一个ServerSocket,不间断监听来自客户端的请求。

     当我们启动Tomcat时:程序会找到Bootstrapmain()方法,同时把args置为["start"]:


然后程序会执行init()方法,设置tomcat运行的环境,初始化类加载器,创建Catalina对象:


接下来程序会执行load()start()方法,这是tomcat启动过程中最重要的两个过程,load()其实是初始化一系列的组件,上面所列的组件都会进行初始化,包括加载配置文件都是在这个过程中实现的;而start()方法就是启动这一系列的组件,当所有组件都启动后,tomcat也就启动完成了。

从这里看,Tomcat启动过程可以简化为3个步骤:

1Bootstrapinit()方法,其实就是设置运行环境和初始化类加载器;

2Bootstrapload()方法,加载相关配置文件,初始化几个主要的顶层组件实例,也就是服务器初始化。

3)启动那些有生命周期的组件,监听用户请求,也就是启动服务器。

        load()方法其实是通过反射来执行Catalinaload()方法,Catalinaload()方法主要作用:

              initDirs()方法初始化tomcat的安装路径;

               createStartDigester()方法解析xml文件;

              getServer().initialize()方法初始化Server组件。



接下来我们看一下server.xml里面的信息到底是什么?为什么能创建server对象呢?


这个就是server.xml的内容,我们可以清晰的看到server下面包含serviceservice下面包含connectorconnector下面包含enginehostcontext,这些就是我们上面所说的tomcat的组件,他们的对应关系也是这样层层包含的关系。

           接下来看看Server真正的初始化过程:StandardServerinitialize():


StandardServiceinitialize()



初始化connectorConnectorinitialize()



初始化协议,Http11Protocolinit()


Endpoint的初始化,Endpointinit()


根据上面的server.xml,connector有两个,所以会初始化两个connectorProtocolHandlerendpoint;

初始化的流程:


所以我们可以知道Bootstrap#load()—>Catalina#load()—>StandardServer#load()—>StandardService#initialize()—>Connector#initialize()—>Http11Protocol#init()—>Endpoint#init()

至此,tomcat的初始化全部完成。



接下来开始启动tomcat服务器:

回到Bootstrap来,Bootstrapstart()方法通过反射来调用Catalina方法的start()方法

来看看Catalinastart()


StandardServerstart()


下面就看看StandardService对象的start方法:

首先启动Container容器,在server.xml中我们知道Container中含有EngineHostContext,所以这里会启动这三个容器,Service中的这个ContainerEngine,所以首先会启动EngineEngine中有HostContext,它们又都属于Container,所以,这里充分的利用了组合模式,这个过程中会创建background后台守护线程,周期性的检查Session是否超时

然后启动执行器executors,这里executors一般为null

最后启动所有的Connector,这个过程会启动两组ProtocolHandlerEndpoint,这个过程是很重要的一个过程,会创建所有的请求线程池,首先先创建一个Acceptor线程来监听当

以上是关于Tomcat是如何启动及运行—对tomcat的源码解析的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat7.0源码分析——启动与停止服务原理

简单看,tomcat源码启动与监听

spring与tomcat的关系逆袭前后的源码设计分析

TOMCAT封神之旅-源码运行及整体架构

233期谈谈 Tomcat 架构及启动过程

面试官:谈谈 Tomcat 架构及启动过程