vlambda博客
学习文章列表

【tomcat】从整体架构去了解tomcat的工作原理和简单优化

tomcat简单入门

  • • 开源的Java Web 应用服务器,实现了Java EE的部分技术规范:Java Servlet、JavaServer Pages、Java Expression Language、Java WebSocket....

  • • Tomcat的核心:Http服务器+Servlet容器

  • • Servlet的规范:Servlet接口+Servlet容器

tomcat架构

tomcat架构简化图.png
  • • 对外交流的连接器(Connector):处理 Socket 连接,负责网络字节流与 Request 和 Response 对象的转化。

  • • 内部处理的容器(Container):加载和管理 Servlet,以及具体处理 Request 请求。因此 Tomcat 设计了两个核心组件连接器(Connector)和容器(Container)来分别做这两件事情。连接器负责对外交流,容器负责内部处理。

Tomcat核心组件

  • • Server组件:指的就是整个 Tomcat 服务器,包含多组服务(Service),负责管理和启动各个Service,同时监听 8005 端口发过来的 shutdown 命令,用于关闭整个容器 。

  • • Service组件:每个 Service 组件都包含了若干用于接收客户端消息的 Connector 组件和处理请求的 Engine 组件。Service 组件还包含了若干 Executor 组件,每个 Executor 都是一个线程池,它可以为 Service 内所有组件提供线程池执行任务。

【tomcat】从整体架构去了解tomcat的工作原理和简单优化

Server与Service组件关系图.png
  • • 连接器Connector组件:连接器对 Servlet 容器屏蔽了不同的应用层协议及 I/O 模型,无论是 HTTP 还是 AJP,在容器中获取到的都是一个标准的 ServletRequest 对象。封装了三个高内聚的功能:

  • • 网络通信:EndPoint 负责提供字节流给 Processor;

  • • 应用层协议解析:Processor 负责提供 Tomcat Request 对象给 Adapter;

  • • tomcat Request/Response 与 ServletRequest/ServletResponse 的转化: Adapter 负责提供 ServletRequest 对象给容器。

【tomcat】从整体架构去了解tomcat的工作原理和简单优化

连接器相关组件.png
  • • ProtocolHandler组件:连接器用 ProtocolHandler 来处理网络连接和应用层协议,包含了 2 个重要部件:EndPoint 和 Processor。

  • • 连接器用 ProtocolHandler 接口来封装通信协议和 I/O 模型的差异,ProtocolHandler 内部又分为 EndPoint 和 Processor 模块,EndPoint 负责底层 Socket 通信,Proccesor 负责应用层协议解析。连接器通过适配器 Adapter 调用容器。

  • • EndPoint:通信端点,即通信监听的接口,是具体的 Socket 接收和发送处理器,是对传输层的抽象,因此 EndPoint 是用来实现 TCP/IP 协议的。

  • • Processor:Processor 用来实现 HTTP/AJP 协议,Processor 接收来自 EndPoint 的 Socket,读取字节流解析成 Tomcat Request 和 Response 对象,并通过 Adapter 将其提交到容器处理,Processor 是对应用层协议的抽象。

  • • Adapter组件:把封装了不同协议,不同请求信息的参数的TomcatRequest对象适配成ServletRequest对象供容器使用。

  • • 容器Container组件:容器,用来装载东西的器具,在 Tomcat 里,容器就是用来装载 Servlet 的。Tomcat 通过一种分层的架构,使得 Servlet 容器具有很好的灵活性。Tomcat 设计了 4 种容器,分别是 Engine、Host、Context 和 Wrapper。这 4 种容器是父子关系。

  • • Engine:引擎,Servlet 的顶层容器,用来管理多个虚拟站点,一个 Service 最多只能有一个 Engine;

  • • Context:Web 应用上下文,包含多个 Wrapper,负责 web 配置的解析、管理所有的 Web 资源。一个Context对应一个 Web 应用程序。

  • • Wrapper:表示一个 Servlet,最底层的容器,是对 Servlet 的封装,负责 Servlet 实例的创建、执行和销毁。

【tomcat】从整体架构去了解tomcat的工作原理和简单优化

tomcat容器.png

Tomcat工作原理

  • • 请求定位:一个请求 URL 最后只会定位到一个 Wrapper 容器,也就是一个 Servlet。

  • • Tomcat 是用 Mapper 组件来完成这个任务的。

  • • Mapper 组件的功能就是将用户请求的 URL 定位到一个 Servlet,它的工作原理是:Mapper 组件里保存了 Web 应用的配置信息,其实就是容器组件与访问路径的映射关系,比如 Host 容器里配置的域名、Context 容器里的 Web 应用路径,以及 Wrapper 容器里 Servlet 映射的路径,你可以想象这些配置信息就是一个多层次的 Map。

  • • 当一个请求到来时,Mapper 组件通过解析请求 URL 里的域名和路径,再到自己保存的 Map 里去查找,就能定位到一个 Servlet。

【tomcat】从整体架构去了解tomcat的工作原理和简单优化

tomcat请求定位.png
  • • 请求在容器中的调用过程:连接器中的 Adapter 会调用容器的 Service 方法来执行 Servlet,最先拿到请求的是 Engine 容器,Engine 容器对请求做一些处理后,会把请求传给自己子容器 Host 继续处理,依次类推,最后这个请求会传给 Wrapper 容器,Wrapper 会调用最终的 Servlet 来处理。

具体实现:Pipeline-Valve管道

  • • Pipeline-Valve 是责任链模式,责任链模式是指在一个请求处理的过程中有很多处理者依次对请求进行处理,每个处理者负责做自己相应的处理,处理完之后将再调用下一个处理者继续处理。

  • • Pipeline 中维护了 Valve 链表,Valve 可以插入到 Pipeline 中,对请求做某些处理。整个调用链的触发是 Valve 来完成的,Valve 完成自己的处理后,调用 getNext.invoke() 来触发下一个 Valve 调用。每一个容器都有一个 Pipeline 对象,只要触发这个 Pipeline 的第一个 Valve,这个容器里 Pipeline 中的 Valve 就都会被调用到。Basic Valve 处于 Valve 链表的末端,它是 Pipeline 中必不可少的一个 Valve,负责调用下层容器的 Pipeline 里的第一个 Valve。

  • • Valve 和 Filter 的区别:Valve 是 Tomcat 的私有机制,与 Tomcat 的基础架构 /API 是紧耦合的。Servlet API 是公有的标准,所有的 Web 容器包括 Jetty 都支持 Filter 机制。Valve 工作在 Web 容器级别,拦截所有应用的请求;而 Servlet Filter 工作在应用级别,只能拦截某个 Web 应用的所有请求。

【tomcat】从整体架构去了解tomcat的工作原理和简单优化

tomcat的请求调用过程.png

Tomcat生命周期

  • • Tomcat生命周期是为了统一管理组件的创建、初始化、启动、停止和销毁的基础上,代码逻辑清晰、可以方便地添加或者删除组件、组件启动和停止不遗漏、不重复!

  • • 一键式启停LifeCycle接口:提供了固定的init()、start()、stop() 和 destroy()方法。

  • • 可扩展性LifeCycle事件:观察者模式,提供了添加监听器和删除监听器的方法。

  • • 重用性LifeCycleBase抽象基类:LifeCycleBase 来实现 LifeCycle 接口,把一些公共的逻辑放到基类中去,比如生命状态的转变与维护、生命周期事件的触发以及监听器的添加和删除等,而子类就负责实现自己的初始化、启动和停止等方法。

Tomcat生命周期类图.png

tomcat可以优化的点

  • • 清理不必要的文件

  • • 清理不必要的 Web 应用

  • • 删除掉 webapps 文件夹下不需要的工程,一般是 host-manager、example、doc 等这些默认的工程,可能还有以前添加的但现在用不着的工程

  • • 清理 不必要的XML 配置

  • • 清理 不必要的JAR 文件

  • • 清理其他文件:比如日志...

  • • 禁止 Tomcat TLD 扫描:可以提高Tomcat的启动速度,并节省JSP编译时间。在conf/context.xml,添加下面的配置。

<JarScanner>
  <JarScanFilter defaultTldScan="false"/>
</JarScanner>
  • • 关闭WebSocket支持:在conf/context.xml中给 Context 标签加一个containerSciFilter属性。

<Context containerSciFilter="org.apache.tomcat.websocket.server.WsSci">
</Context>
  • • 关闭JSP支持:在conf/context.xml中给 Context 标签加一个containerSciFilter属性。

<Context containerSciFilter="org.apache.tomcat.websocket.server.JasperInitializer">
</Context>
<!-- WebSocket 和 JSP都关闭 -->
<Context containerSciFilter="org.apache.tomcat.websocket.server.WsSci | org.apache.tomcat.websocket.server.JasperInitializer">
</Context>
  • • 禁止Servlet注解扫描:Servlet 3.0 引入了注解 Servlet,Tomcat 为了支持这个特性,会在 Web 应用启动时扫描你的类文件,因此如果你没有使用 Servlet 注解这个功能,可以告诉 Tomcat 不要去扫描 Servlet 注解。在web应用的web.xml中配置

<web-app metadata-complete="true">
</web-app>
  • • 并行启动多个 Web 应用:Tomcat 启动的时候,默认情况下 Web 应用都是一个一个启动的,等所有 Web 应用全部启动完成,Tomcat 才算启动完毕。如果在一个 Tomcat 下你有多个 Web 应用,为了优化启动速度,可以配置多个应用程序并行启动。修改conf/server.xml中Host 标签的 startStopThreads 属性.

<Host startStopThreads="0">
</Host>

结束语

• 获取更多本文的前置知识文章,以及新的有价值的文章,让我们一起成为架构师!

• 接下来的目标是深入分析JVM、tomcat、redis