Tomcat核心架构和启动流程解析

HTTP请求流程

浏览器发起一个HTTP请求的流程如下:

  1. 用户通过浏览器进行了一个操作,比如输入地址并按下回车、点解某个超链接。
  2. 浏览器向服务器发起TCP连接建立请求。
  3. 浏览器与服务器通过三次握手建立了TCP连接请求。
  4. 浏览器将请求数据打包封装成一个HTTP协议格式的数据包。
  5. 浏览器将打包好的HTTP数据包通过建立的TCP连接发送到服务端。
  6. 服务端程序接收到数据包后,按照http协议解析数据包。
  7. 服务端程序对解析后的数据包进行业务逻辑处理,比如提供静态资源或者调用服务端程序进行获取动态结果。
  8. 服务器将相应结果打包封装成HTTP协议格式的数据包。
  9. 服务器将数据包通过TCP连接发送到浏览器。
  10. 浏览器收到数据包后按照HTTP协议解析数据包,然后解析数据。假设是HTML。
  11. 浏览器将HTML数据展示在页面上。
  12. 如果TCP连接时短连接的话,就直接进行4次握手释放连接,如果是长连接的话,就不释放连接,下次发送HTTP数据包也采用这个连接。

在这里插入图片描述

Tomcat的两个核心功能

根据上面分析的一个HTT请求的大概流程,可以知道Tomcat要实现核心功能有两个。

  1. 处理Socket连接,负责网络字节流的的接收和发送和Request和Response对象的转化。
  2. 加载和管理Servlet,以及处理Request请求并生成response响应。

因此,Tomcat设计了两个核心组件:连接器(Connector)和 容器(Container)来分别做这两件事情,连接器负责对外交流,容器负责内部请求处理。

在这里插入图片描述
service不是一个新的东西,只是把Connector和Container组装起来的一个对象,一个Service可以有多个Connector,但是只能有一个Container,也就是多个Connector对一个Container,单独的Connector和Container都不能对外服务,只有组装成一个Service才能对外服务。

一个Tomcat可以包含多个service。

连接器Coyote
  • Coyote是Tomcat连接器框架的名称,是Tomcat服务器提供的供客户端访问的外部接口,客户端通过Coyote与服务器建立连接,发送请求并接受响应。
  • Coyote封装了底层的网络通信(Socket请求及响应处理),为Catalina容器提供了统一接口。使Catalina容器与具体请求协议与具体的IO方式完全解耦。Coyote将Socket请求连接封装成Request对象,交由Catalina容器进行处理,处理请求完成后,Catalina通过Coyote提供的Response对象将结果写入输出流。
  • Coyote作为独立模块,只负责具体协议和IO操作的处理工作,和servlet具体规范实现没有直接关系,Request和Response对象也并未实现servlet规范对应的接口,而是在Catalina中将他们进一步封装为ServletRequest和ServletResponse。

在这里插入图片描述

IO模型与协议

在Coyote中,Tomcat支持多种应用层协议和IO模型。

IO模型:自Tomcat8.5起,移除了BIO模型。

IO模型描述
NIO非阻塞IO,采用Java NIO类库实现
NIO2异步IO,采用JDK7的最小的NIO2库实现的
APR采用Apache可移植运行库实现的,是C/C++编写的本地库,如果选择该方式,需要单独安装APR库

支持的应用层协议:

协议描述
HTTP/1.1大部分web应用采用的协议
AJP用于和web服务器集成(比如Apache),以实现对静态资源的优化以及集群部署,当前支持AJP1.3
HTTP/2HTTP大幅度提升了Web性能,是下一代 HTTP协议,8.5以及9.0之后支持
连接器组件

在这里插入图片描述
上图是连接器组件的组件图。
Endpoint:

  • Coyote通信的端点,即通信监听端口的接口。是具体的Socket发送和接收的处理器,是对传输层的抽象,因此Endpoint是用来实现TCP协议的。
  • Tomcat并没有Endpoint接口,而是提供了一个AbstractEndpoint抽象类,里面定义了两个内部类,Acceptor和SocketProcessor。Acceptor监听Socket连接请求。SocketProcessor用于处理接收到的Socket连接请求,他实现Runnable接口,在Run方法中调用协议处理组件Processor进行处理,为了提高处理能力,SocketProcessor被提交到线程池进行处理,而这个线程池是jdk的Executor接口。

Processor:

  • coyote协议处理的接口,如果说Endpoint是用于实现TCP/IP协议的,那么Processor是用于实现HTTP、AJP协议的。Processor接收来自Endpoint的Socket,读取字节流解析成Tomcat的Request对象。并通过Adapter提高给容器进行处理。Processor是对应用层协议的抽象。

ProtocolHandler:

  • coyote接口,通过Endpoint和Processor实现针对具体协议的处理实现,Tomcat按照协议和IO模型提供了6个实现了,AjpNioProtocol、AjpNio2Protocol、AjpAprProtocol、Http11NioProtocol、Http11Nio2Protocol、Http11AprProtocol。我们在配置conf/server.xml时,至少要指定具体的ProtocolHandler,当然也可以指定协议名称。

Adapter:
由于协议不同,客户端发送过去的请求协议也不尽相同,Tomcat定义了自己的Request和Response类来存放这些请求信息,ProtocolHandler负责接收并解析请求生成对应的Request对象,但是这个对象并不是标准的ServletRequest,也就是说,不能用Request对象作为参数来调用容器,Tomcat设计者的解决方案是通过引入CoyoteAdapter,这是适配器模式的经典应用,连接器调用CoyoteAdapter的service方法,传入的是Tomcat的Request对象,然后CoyoteAdapter将Request对象转化成ServletRequest对象,再以该对象为参数,调用容器的service方法。

容器Catalina

Catalina是Tomcat容器的实现,包含了所有的容器组件,涉及到安全、会话、集群、管理等,他通过松耦合方式继承coyote,已完成安装请协议进行数据读写,同时还包括启动入口,shell程序等等。

Tomcat的模块分层示意图
在这里插入图片描述
Tomcat本质上是一款servlet容器,因此Catalina是servlet的核心,其他模块组件是对Catalina提供支撑,比如Coyote模块提供IO、连接、协议的处理,Naming提供命名服务的支撑,Juli提供服务器日志的支撑。jasper提供jsp解析的支撑。

在这里插入图片描述
这是Tomcat源码的部分,每个包代表了一个模块组件。

在这里插入图片描述
上图是Catalina的架构图。Catalina负责管理server,而server表示整个服务器,server下面有多个服务service,每个service都包含多个Connector(coyote实现)和一个Container。在Tomcat启动的时候,会初始化一个Catalina实例。

Catalina各个组件的职责:

  • Catalina:负责解析Tomcat配置文件,并以此来创建服务器Server组件,并根据命令来对其进行管理。
  • Server:Server服务器组件表示整个Catalina、servlet容器以及其他组件,负责组装并启动servlet引擎,Tomcat连接器。server通过实现Lifecycle接口,提供了一种优雅的启动和关闭整个系统的方式。
  • Service:服务Server的内部组件,一个Server包含多个Service,他将多个Connector绑定到一个Container上。
  • Connector:连接器,处理与客户端的通信,他负责接收客户端请求,转发给相应的容器处理,然后将结果响应给客户端。
  • Container:容器,负责处理用户的servlet请,并返回结果给Web用户的模块。
Container结构

Tomcat设计了4种容器,分别是Engine、Host、Context和Wrapper。这四种容器不是平级关系,而是父子关系,Tomcat通过一种分层架构,使得servlet容器具有很好的灵活性。

在这里插入图片描述

  • Engine:表示整个Catalina的servlet引擎,用于管理多个虚拟站点,一个Service最多只能有一个且必须有一个Engine。
  • Host:代表一个虚拟主机,或者说一个站点,可以给Engine配置多个虚拟主机。
  • Context:表示一个Web应用程序,一个Web应用程序可以包含多个wrapper。
  • Wrapper:表示一个servlet,Wrapper作为容器中的最底层,不包含子容器。
Executor

Executor是Tomcat的线程池组件,其本质是jdk的juc包下的Executor接口。
在这里插入图片描述
只是多继承了一个生命周期接口,和声明多了一个execute方法。

Tomcat启动流程

启动流程时序图:
在这里插入图片描述
windows系统是startup.bat脚本,linux是start.sh脚本。

  1. 执行BootStrap的main方法。这是tomcat启动的入口。
  2. 执行BootStrap的init初始化方法。
  3. 执行BootStrap的load方法。
  4. 由BootStrap调用Catalina的init方法,创建server。
  5. 由Catalina调用server的init方法。
  6. 由server调用service的init方法。
  7. 由service调用Engine的init方法。
  8. 由Engine调用Host的init方法。
  9. 由Host调用context的init方法。
  10. 由 service调用Executor的init方法。
  11. 由service调用connector的init方法。
  12. 由connector调用protocolHandler的init方法。
    至此,Tomcat初始化完毕,然后BootStrap调用自己的start的方法,然后按照初始化顺序调用各组件的start方法。

可以看到,每个组件都有init方法和start等生命周期方法,所以Tomcat在设计的时候,基于生命周期管理抽象成了一个Lifecycle接口,而组件Server、Service、Container、Executor、Connector、Engine等都直接或者解决实现了该接口,从而具有init、start、stop、destroy生命周期核心方法。

在这里插入图片描述

每个组件提供的基本实现类如下:

在这里插入图片描述

贴部分源码:BootStrap的全限定名是org.apache.catalina.startup.Bootstrap
在这里插入图片描述
这里调用bootStrap的init方法。BootStrap的init方法主要创建Catalina实例。
在这里插入图片描述

在这里插入图片描述
这是main方法的后半部分,因为是启动,所以命令名是start,所以会进入红框中的分支,执行BootStrap的load方法。

在这里插入图片描述

上面通过反射调用Catalina对象的load方法,可以看到方法名为load,对象为Catalina。
在这里插入图片描述
这个是Catalina init方法的片段。主要是创建一个Digester实例。

在这里插入图片描述
上面是Catalina的init方法的一部分,执行server的初始化。

在这里插入图片描述
执行server的init方法实际上是执行LifecycleBase基类的init方法,然后使用模板方法模式调用Server的initInternal方法。

在这里插入图片描述
这里是StandardServer的initInternal方法的片段,这里执行service的初始化,因为一个server可以包含多个servic,所以要使用循环。

剩下的部分就不贴了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值