深刻拆解Tomcat & Jetty-学习笔记(2)模块二之tomcat系统架构

总体架构

概述

咱们知道若是要设计一个系统,首先是要了解需求。 Tomcat 要实现 2 个核心功能:nginx

  1. 处理 Socket 链接,负责网络字节流与 Request 和 Response 对象的转化。
  2. 加载和管理 Servlet,以及具体处理 Request 请求。 所以 Tomcat 设计了两个核心组件链接器(Connector)和容器(Container)来分别作这两件事情。链接器负责对外交流,容器负责内部处理。

从图上你能够看到,最顶层是 Server,这里的 Server 指的就是一个 Tomcat 实例。一个 Server 中有一个或者多个 Service,一个 Service 中有多个链接器和一个容器。链接器与容器之间经过标准的 ServletRequest 和 ServletResponse 通讯。web

链接器的设计

什么是链接器

链接器对 Servlet 容器屏蔽了协议及 I/O 模型等的区别,不管是 HTTP 仍是 AJP,在容器中获取到的都是一个标准的 ServletRequest 对象。apache

链接器的功能细化

监听网络端口。 接受网络链接请求。 读取网络请求字节流。 根据具体应用层协议(HTTP/AJP)解析字节流,生成统一的 Tomcat Request 对象。 将 Tomcat Request 对象转成标准的 ServletRequest。 调用 Servlet 容器,获得 ServletResponse。 将 ServletResponse 转成 Tomcat Response 对象。 将 Tomcat Response 转成网络字节流。 将响应字节流写回给浏览器。浏览器

链接器的子模块

经过分析链接器的详细功能列表,咱们发现链接器须要完成 3 个高内聚的功能:tomcat

  • 网络通讯。
  • 应用层协议解析。
  • Tomcat Request/Response 与 ServletRequest/ServletResponse 的转化。 这个三个功能对应了组件来完成其功能:
  • endpoint :是通讯端点,对传输层的抽象,它能够有不一样的I/O模型的实现 如非阻塞 I/O、异步 I/O 或者 APR
  • processor :Processor 用来实现 HTTP 协议,Processor 接收来自 Endpoint 的 Socket,读取字节流解析成 Tomcat Request 和 Response 对象,并经过 Adapter 将其提交到容器处理,Processor 是对应用层协议的抽象。这一层能够有Http协议的变化,如 HTTP、HTTPS、AJP
  • adapter

ProtocolHandler 组件

ProtocolHandler 组件是将EndPoint和Processor两个组件进行了封装 下图为两个维度不一样的组合网络

链接器组件图

Endpoint 接收到 Socket 链接后, 生成一个 SocketProcessor 任务提交到线程池去处理, SocketProcessor 的 run 方法会调用 Processor 组件去解析应用层协议, Processor 经过解析生成 Request 对象后, 会调用 Adapter 的 Service 方法。架构

Adapter 组件

Adapter 组件完成 Tomcat Request ->Servlet Request的转换 CoyoteAdapter 负责将 Tomcat Request 转成 ServletRequest,再调用容器的 service 方法。app

为何要多一层adapter?

问题:在processor直接转换为容器的servletrequest和servletresponse不是更好,为何要先转化Tomcat的request和response,再用adapter作一层转换消耗性能?异步

回答:若是链接器直接建立ServletRequest和ServletResponse对象的话,就和Servlet协议耦合了,设计者认为链接器尽可能保持独立性,它不必定要跟Servlet容器工做的。另外对象转化的性能消耗仍是比较少的,Tomcat对HTTP请求体采起了延迟解析的策略,也就是说,TomcatRequest对象转化成ServletRequest的时候,请求体的内容都还没读取呢,直到容器处理这个请求的时候才读取的。性能

tomcat和nginx的性能差别出现的缘由?
  1. Nginx/Apche通常作反向代理和处理静态HTML资源,作的事情相对来讲简单,KPI就是要快,所以用C语言实现,直接调用操做系统API,充分利用操做系统的高级特性。

  2. 而Tomcat用来处理动态请求,还须要跑Java应用,所以用Java实现,所以”快“不是它主要的KPI。Java调用操做系统API要经过JNI,无形中有性能损耗。另外Tomcat经过使用Apache APR本地库来作I/O通讯,性能已经跟Apache、Nginx接近了。

同一个tomcat能够设置多个端口号来启动多个应用吗?

能够的,在server.xml配置多个service,或者同一个service里配置多个connector

多层容器的设计

容器的层次结构

omcat 设计了 4 种容器,分别是 Engine、Host、Context 和 Wrapper。

一个 Tomcat 实例包含一个service 一个 Service 包含一个 Engine和多个链接器, 一个 Engine 包含多个 Host, 一个 Host包 含多个Context 一个 Context包含多个 Wrapper 一个 Wrapper包含一个servlet

请求定位 Servlet 的过程

  • 由 Mapper 组件完成, Mapper 组件保存了容器组件与访问路径的映射关系, 根据请求的 URL 进行定位

    • 端口号定位出 Service 和 Engine
    • 域名定位出 Host
    • URL 路径定位出 Context Web 应用
    • URL 路径定位出 Wrapper ( Servlet )
  • 在各个层次定位过程当中, 都会对请求作一些处理

    • 经过 Pipeline-Valve 实现容器间的互相调用 ( 责任链模式 )
    • valve 表示一个处理点 ( 如权限认证, 日志等), 处理请求; valve 经过链表串联, 并由 pipeline 维护
    • valve 会经过 getNext().invoke() 调用下一个 valve, 最后一个 valve ( Basic ) 调用下一层容器的 pipeline 的第一个 valve
    • Adapter 调用 Engine pipeline 的第一个 valve
    • Wrapper 最后一个 valve 会建立一个 Filter 链, 并最终调用 Servlet 的 service 方法

  • valve 与 filter 对比
    • valve 是 Tomcat 的私有机制, Filter 是 Servlet API 公有标准
    • valve 工做在容器级别, 拦截全部应用; Servlet Filter 工做在应用级别, 只能拦截某个应用的请求
Tomcat 内的 Context 组件跟 Servlet 规范中的 ServletContext 接口有什么区别?跟 Spring 中的 ApplicationContext 又有什么关系?
  • Servlet规范中ServletContext表示web应用的上下文环境,而web应用对应tomcat的概念是Context,因此从设计上,ServletContext天然会成为tomcat的Context具体实现的一个成员变量
  • tomcat内部实现也是这样完成的,ServletContext对应tomcat实现是org.apache.catalina.core.ApplicationContext,Context容器对应tomcat实现是org.apache.catalina.core.StandardContext。ApplicationContext是StandardContext的一个成员变量。
  • Spring的ApplicationContext以前已经介绍过,tomcat启动过程当中ContextLoaderListener会监听到容器初始化事件,它的contextInitialized方法中,Spring会初始化全局的Spring根容器ApplicationContext,初始化完毕后,Spring将其存储到ServletContext中。总而言之,Servlet规范中ServletContext是tomcat的Context实现的一个成员变量,而Spring的ApplicationContext是Servlet规范中ServletContext的一个属性。
Basic valve 有些疑惑。好比engine容器下有多个host容器,那engine容器的basic valve是怎么知道要指向哪一个host容器的value呢?

Mapper组件在映射请求的时候,会在Request对象中存储相应的Host、Context等对象,这些选定的容器用来处理这个特定的请求,所以Engine中的Valve是从Request对象拿到Host容器的。

生产环境中, 配的都是一个 tomcat 对应一个应用, 多个应用就用多个tomcat ,它和一个 tomcat 加载多个应用有什么区别么?

在同一个Tomcat实例里部署多个Web应用是为了节省内存等资源,不过配置部署有点复杂,应用之间互相影响,加上如今硬件成本将低,多应用部署比较少见了。

备注

本文是我我的学习了李号双老师的专栏课程以后,结合专栏文章和老师对同窗答疑整理的学习笔记。仅供分享。更多精彩内容,你们能够扫描下方二位码,在极客时间订阅李号双老师的《深刻拆解Tomcat & Jetty》。获取一手学习资料。

相关文章
相关标签/搜索