1.Http工作原理

<mark>HTTP协议</mark>是<mark>浏览器</mark>与<mark>服务器</mark>之间的<mark>数据传输协议</mark>.作为<mark>应用层</mark>协议.<mark>HTTP</mark>是<mark>基于TCP/IP协议</mark>来传递数据的(HTML文件,图片,查询结果等),<mark>HTTP协议不涉及数据包(Packet)传输</mark>.主要规定了<mark>客户端和服务器之间的通信格式</mark>.


从图上你可以看到,这个过程:

  1. 用户通过浏览器进行了一个操作,比如输入网址并回车,或者点击链接,接着浏览器获取这个事件.
  2. <mark>浏览器向服务端发出TCP连接请求.</mark>
  3. 服务程序接收浏览器的连接请求,<mark>并经过TCP三次握手建立连接.</mark>
  4. 浏览器将请求数打包成一个<mark>HTTP协议格式的数据包</mark>
  5. 浏览器将该数据包推入网络,数据包经过网络传输,最终到达服务端程序
  6. 服务端程序拿到这个数据包后,同样以<mark>HTTP协议格式解包</mark>,获取到客户端的意图.
  7. 得知客户端意图后进行处理.
  8. <mark>服务器将响应结果按照HTTP协议格式打包</mark>
  9. 服务器将响应数据包推入网络,数据包经过网络传输最终到达浏览器
  10. 浏览器拿到数据包后,以HTTP协议的格式解包,然后解析数据,假设数据是HTML
  11. 浏览器将HTML文件展示在页面上

2.Tomcat整体架构

2.1 Http服务器请求处理

浏览器发送给服务器的是一个HTTP格式的请求,HTTP服务器接收到这个请求后,需要调用服务端程序来处理,所谓的服务端程序就是你写的Java类,一般来说不同的请求需要不同的Java类来处理.

  1. 图1,表示HTTP服务器直接调用具体业务类,它们时<mark>紧耦合</mark>的
  2. 图2,HTTP服务器不用直接调用业务类,<mark>而是把请求交给容器来处理,容器通过Servlet接口调用业务类.因此Servlet接口和Servlet容器的出现,达到了HTTP服务器与业务类的解耦的目的的,而Servlet容器这一整套规范叫做Servlet规范.Tomcat按照Servlet规范的要求实现了Servlet容器,同时他们也具有HTTP服务器的功能,作为Java程序员,如果我们实现新的业务功能,只需要实现一个Servlet,并把它注册到Tomcat(Servlet容器)中,剩下的事就由Tomcat帮我们处理.</mark>
2.2 Servlet容器工作流程


<mark>当客户请求某个资源时,HTTP服务器会用一个ServletRequest对象把客户的请求信息封装起来,然后调用Servlet容器的service方法,Servlet容器拿到请求后,根据请求的URL和Servlet的映射关系,找到相应的Servlet,如果Servlet还没有被加载,就用反射机制创建这个Servlet,并调用Servlet的init方法来完成初始化,接着调用Servlet的service方法来处理请求,把ServletResponse对象返回给HTTP服务器,HHTP服务器会把响应发送给客户端.</mark>

2.3 Tomcat整体架构

我们知道如果设计一个系统,首先是要了解需求,我们已经了解了Tomcat要实现两个核心功能:

  1. 处理Socke连接,负责网络字节流与Request和Response对象转换
  2. 加载和管理Servlet,以及具体处理Request请求.
    因此Tomcat设计了两个核心组件连接器和容器来分别做这两件事.连接器负责对外交流,容器负责内部处理.
2.3.1 连接器 - Coyote

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

2.3.2 IO模型与协议

在Coyote中,Tomcat支持的多种I/O模型和应用层协议,具体包含如下:
Tomcat支持IO模型(自8.5/9.0版本起,Tomcat移除了BIO的支持)

Tomcat 支持的应用层协议

协议分层

在8.0之前,Tomcat默认采用的I/O方式为BIO,之后改为NIO.无论NIO,NIO2还是APR,在性能方面均优于以往的BIO,如果采用APR,甚至可以达到Apache HTTP Server的影响性能.

Tomcat为了实现支持多种I/O模型和应用协议,一个容器可能对接多个连接器,就好比一个房间有多个门,但是单独的连接器或者容器都是不能对外提供服务,需要把他们组装起来才能工作,组装后这个整体叫做Service组件,这里请注意,Service本身没有做什么重要的事,只是在连接器和容器外面多包了一层,把他们组装起来,Tomcat内可能有多个Service,这样的设计也是处于灵活的考虑.在Tomcat中配置多个Service,可以实现通过不同的端口号来访问同一台机器上部署的不同应用.

2.3.3 连接器组件


连接器中的各个组件的作用:
<mark>EndPoint</mark>
1.EndPoint:Coyote通信端点,即通信监听的端口,是具体Socket接收和发送处理器,是对传输层的抽象,因此EndPoint来实现TCP/IP协议的
2.Tomcat并没有EndPoint接口,而是提供了一个抽象类AbstractEndPoint,里面定义了两个内部类:Acceptor和SocketProcessor.Acceptor用于监听Socket连接请求,SocketProcessor.Acceptor用于处理接收到的Socket请求,他实现Runnable接口,在Run方法里面调用协议处理组件Processor进行处理.为了提高处理能力,SocketProcessor.Acceptor被提交到线程池来执行.而这个线程池叫做执行器(Executor).
<mark>Processor</mark>
Processor:Coyote协议处理接口,如果说EndPoint是用来实现TCP/IP协议的,那么Processor用来实现HTTP协议.Processor接收来自EndPoint的Socket,读取字节流解析成Tomcat Request和Response对象,并通过Adapter将其提交到容器处理,Processor是对应应用层协议的抽象.

<mark>Adapter</mark>
由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat定义了自己的Request类来"存放"这些请求信息,ProtocolHandler接口负责解析请求并生成Tomcat Request类,但是这个Request对象不是标准的ServletRequest,也就意味着,不能用Tomcat Request作为参数来调用容器.Tomcat的设计者的解决方案是引入CoyoteAdapter,这是个适配器模式的经典运用,连接器调用CoyoteAdapter的Service方法,传入的是Tomcat Reuest对象,CoyoteAdapter负责将Tomcat Request转成ServletRequest,再调用容器的Service方法.