组件介绍:
Tomcat 最重要的是两个组件是:Connector(连接器) 和 Container(容器/集装箱),Connector 组件是可以被替换,这样可以提供给服务器设计者更多的选择,因为这个组件是如此重要,不仅跟服务器的设计的本身,而且和不同的应用场景也十分相关,所以一个 Container 可以选择对应多个 Connector。
多个 Connector 和一个 Container 就组成一个 Service,有了 Service 就可以对外提供服务了,但是 Service 还要一个生存的环境, Server 就提供了这样一个环境。所以整个 Tomcat 的生命周期由 Server 控制。
下面来一层层的看,首先是Server,什么是server呢?
Server
Server 要完成的任务很简单,就是要能够提供一个接口让其它程序能够访问到 Service 集合,同时要维护它所包含的所有 Service 的生命周期,包括如何初始化、如何结束服务、如何找到别人要访问的 Service。还有一些次要的任务,如记录Service运行日志,维护Session等等。Server包含的组件结构如下:
Service
Service 是在 Connector 和 Container 外面多包一层,把它们组装在一起,向外面提供服务,一个 Service 可以设置多个 Connector,但是只能有一个 Container 容器。当然Service不仅仅包含这两个组件, Service 接口的方法列表如下:
Container
Container本意是集装箱的意思,是一个接口,定义了下属的各种容器,重要的是Wrapper、Host、Engine、Context等
Engine(引擎)
负责处理来自相关联的service的所有请求,处理后,将结果返回给service,而connector是作为service与engine的中间媒介出现的。
一个engine下可以配置一个默认主机,每个虚拟主机都有一个域名。当engine获得一个请求时,它把该请求匹配到虚拟主机(host)上,然后把请求交给该主机来处理。
Engine有一个默认主机,当请求无法匹配到任何一个虚拟主机时,将交给默认host来处理。Engine以线程的方式启动Host。
Host
代表一个虚拟主机,每个虚拟主机和某个网络域名(Domain Name)相匹配。
每个虚拟主机下都可以部署一个或多个web应用,每个web应用对应于一个context,有一个context path。
当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理匹配的方法是“最长匹配”,所以一个path==””的Context将成为该Host的默认Context所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配。
Context
一个Context对应于一个Web应用,一个Web应用由一个或者多个Servlet组成Context在创建的时候将根据配置文件$CATALINA_HOME/conf/web.xml
和$ WEBAPP_HOME/WEB-INF/web.xml
载入Servlet类。当Context获得请求时,将在自己的映射表(mapping table)中寻找相匹配的Servlet类,如果找到,则执行该类,获得请求的回应,并返回。
Wrapper
Wrapper 代表一个 Servlet,它负责管理一个 Servlet,包括的 Servlet 的装载、初始化、执行以及资源回收。Wrapper 是最底层的容器,它没有子容器了,所以调用它的 addChild 将会报错。
Wrapper 的实现类是 StandardWrapper,StandardWrapper 还实现了拥有一个 Servlet 初始化信息的 ServletConfig,由此看出 StandardWrapper 将直接和 Servlet 的各种信息打交道。
Connector
Connector将在某个指定的端口上来监听客户的请求,把从socket传递过来的数据,封装成Request,传递给Engine来处理,并从Engine处获得响应并返回给客户。
Tomcat通常会用到两种Connector:
- Http Connector 在端口8080处侦听来自客户browser的http请求。 AJP Connector
- 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求。
Lifecycle
现实生活中大部分的事物都有生命周期,就像人的生老病死一样。
在编程中也有很多对象是具有生命周期的,从初始化、运行、回收等 会经历几个不同的阶段。 在tomcat中容器相关的好多组建都实现了Lifecycle接口,当tomcat启动时,其依赖的下层组件会全部进行初始化。 并且可以对每个组件生命周期中的事件添加监听器。
例如当服务器启动的时候,tomcat需要去调用servlet的init方法和初始化容器等一系列操作,而停止的时候,也需要调用servlet的destory方法。而这些都是通过org.apache.catalina.Lifecycle接口来实现的。由这个类来制定各个组件生命周期的规范。
LifecycleListener
在Lifecycle的介绍中提到,Lifecycle会对每个组件生命周期中的事件添加监听器,也就是addLifecycleListener(LifecycleListener listener)方法,而LifecycleListener就是上面提到的监听器。
LifecycleEvent
顾名思义,就是当有监听事件发生的时候,LifecycleEvent会存储时间类型和数据
/**
* Construct a new LifecycleEvent with the specified parameters.
*
* @param lifecycle Component on which this event occurred
* @param type Event type (required)
* @param data Event data (if any)
*/
public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
super(lifecycle);
this.type = type;
this.data = data;
}
tomcat 的启动过程
tomcat的启动的起点是Server.start()方法,在这里它会依次启动Container
和 Connector
相关组件,最后到达EndPoint(Tomcat启动的Socket管理者),完成整个启动过程。如下图是个简易过程:
具体实现过程
StartFirst
/**
* Start the server.
*
* @throws LifecycleException Start error
*/
public void start() throws LifecycleException {
getServer();
getConnector();
server.start();
}
server启动之前需要准备好Server和Connector,server的默认实现是StandardServer, start()方法在其父类LifecycleBase中
注:LifecycleBase还是
StandardService
,StandardEngine
,StandardHost
,StandardContext
等的父类,所以当调用这些类的start()
方法时其实都是调用此处的start()
方法,而最重要的是在start()
方法中会调用startInternal()
,startInternal()
在LifecycleBase中是抽象方法,具体实现由各个实现类自己定义。
startServer
启动server其实就是启动service容器,靠StandardService中的startInternal()实现方法,参考代码如下:
startService
启动service其实就是启动engine容器和connector容器,是在StandardEngine中实现的。参考代码如下:
启动Engine
启动engine其实就是启动host容器(多线程),是在StandardHost中实现,参考代码如下:
启动Host
启动Host的方式和上图一样,都是以线程的方式启动子Container,这里Host的children为Context
启动Context(上下文)
启动Wrapper
loadServlet(加载servlet):
它基本上描述了对 Servlet 的操作,当装载了 Servlet 后就会调用 Servlet 的init
方法,同时会传一个 StandardWrapperFacade
对象给 Servlet,这个对象包装了 StandardWrapper,ServletConfig 与它们的关系图如下:
启动Connector
Tomcat的Connector是Coyote connector的一种实现,这是tomcat的官方解释:The Coyote HTTP/1.1 Connector element represents a Connector component that supports the HTTP/1.1 protocol. It enables Catalina to function as a stand-alone web server, in addition to its ability to execute servlets and JSP pages.
Tomcat8之后默认使用nio作为接受请求策略,默认在Service启动的时候进行初始化,当然也可以单独启动,在默认的构造函数中会初始化ProtocolHandler
tomcat中支持两种协议的连接器:HTTP/1.1与AJP/1.3
HTTP/1.1协议负责建立HTTP连接,web应用通过浏览器访问tomcat服务器用的就是这个连接器,默认监听的是8080端口;
AJP/1.3协议负责和其他HTTP服务器建立连接,监听的是8009端口,比如tomcat和apache或者iis集成时需要用到这个连接器。
Connector
的启动其实就是ProtocolHandler
的启动,如下图:
ProtocolHandler的类结构如下图:
Connector
的startInternal
方法调用了ProtocolHandle
的start
方法,这个start
方法就在AbstractProtocol
中,如下图:
EndPoint启动
EndPoint是tomcat启动的终点,EndPoint是Tomcat启动的Socket管理者(注:通过类图可以看出AbstractEndpoint已经脱离了Lifecycle和LifecycleListener体系,所以它只是一个简简单单的Socket管理者),因为是由他直接启动默认的Nio,在启动的时候先看看类结构图:
EndPoint能做什么呢?来看一下他的方法:
createAcceptor
、createExecutor
等方法都是在初始化EndPoint很重要方法,因为在接收请求的时候,通过Acceptor的接收,经过重重模块,才能一路到达Servlet
那么EndPoint的启动,如下图:
在这个地方会启动很多的线程,这些线程大多是用于tomcat接收请求的作用。关于tomcat的接收请求流程,后续会继续积累。
作者:onlyHalfSoul
链接:https://www.jianshu.com/p/8d20e1a057b1
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。