Tomcat 汤姆猫,哈哈, 基本属于那种大家天天用, 反而很容易忽视的角色. Tomcat 架构解析这本书详细地介绍了 Tomcat 的总体架构, 主要组件以及配置文件的使用, 书中掺杂了大量的源码来介绍业务流程, 这边都做了删减, 有兴趣的可以阅读原版.另外 Tomcat 官网也有相关文档, 只是比较混乱.
如有侵权,请联系删除.
Tomcat 是全世界最著名的基于 Java 语言的轻量级应用服务器, 是一款完全开源免费的 Servlet 容器实现. 同时, 它支持 HTML, JS 等静态资源的处理, 因此又可以作为轻量级 Web 服务器使用.
Tomcat 最初由 Sun 公司的软件架构师 James Duncan Davidson 开发, 该项目于 1999 年与 Apache 软件基金会旗下的 JServ 项目合并, 即为现在的 Tomcat.
本章主要包含如下几个部分.
为了使读者能更深刻地理解 Tomcat 的相关组件概念, 我们将采用一种启发式的讲解方式来介绍 Tomcat 的总体设计.
服务器最基本的描述:它接收客户端发来的请求数据并进行解析,完成相关业务处理,然后把处理结果作为响应返回给客户端.
通常情况下, 我们通过使用 Socket 监听服务器指定端口来实现该功能.
一个最简单的服务器设计如下图所示
将请求监听与请求处理放在一起扩展性很差, 比如我们想适配多种网络协议(AJP 协议, HTTP 协议等), 但是请求处理过程却相同的时候.
但是, 这个设计有个明显的缺陷, 即如何知晓来自某个 Connector 的请求由哪个 Container 处理呢?
在 Tomcat 中,Container 是一个更加通用的概念。
为了与 Tomcat 中的组件命名一致,我们将 Container 重新命名为 Engine,用以表示整个 Servlet 引擎。
我们需要在 Engine 容器中支持管理应用,当接收到 Connector 的处理请求时,Engine 容器能够找到一个合适的 Web 应用来处理。
我们使用 Context 来表示一个 Web 应用,并且一个 Engine 可以包含多个 Context。
如果我们希望只运行一个服务器实例, 但提供多个域名的服务, 可以将每个域名视为一个虚拟的主机, 在每个虚拟主机下包含多个 Web 应用.
我们用 Host 表示虚拟主机的概念, 一个 Host 可以包含多个 Context.
另外, 在一个 Web 应用中, 可包含多个 Servlet 实例以处理来自不同链接的请求.
在 Tomcat 中, Servlet 定义被称为 Wrapper, 基于此修改后的设计如图 2-7 所示.
补一张更形象的总体架构图
Connector 需要包含如下几项功能:
只有这样才能保证将接收到的客户端请求交由与请求地址匹配的容器处理.
我们知道,Tomcat 支持多协议,默认支持 HTTP 和 AJP。
同时,Tomcat 还支持多种 IO 方式,包括 BIO(8.5版本之后移除)、NIO、APR.
而且在 Tomcat 8 之后新增了对 NIO2 和 HTTP/2 协议的支持。
因此,对协议和 IO 进行抽象和建模是需要重点关注的.
Tomcat 提供了 Executor 接口来表示一个可以在组件间共享的线程池(默认使用了JDK5提供的线程池技术),该接口同样继承自 Lifecycle,可按照通用的组件进行管理。
线程池的共享范围如何确定?
在 Tomcat 中 Executor 由 Service 维护,因此同一个 Service 中的组件可以共享一个线程池。
本节将主要介绍 Tomcat 的类加载机制,包括 Tomcat 的类加载器层级设计以及 Web 应用的类加载过程。
我们都知道 JVM 默认提供了 3 个类加载器,它们以一种父子树的方式创建,同时使用委派模式确保应用程序可通过自身的类加载器(System)加载所有可见的Java类。结构如图2-19所示。
Tomcat 提供了 3 个基础的类加载器和 Web 应用类加载器, 而且这 3 个类加载器指向的路径和包列表均可以由 catalina.properties 配置.
本章从多个方面讲述了 Tomcat 的总体架构。
本章主要介绍 Tomcat 的 Servlet 容器实现 Catalina.
Catalina 通过解析 server.xml 创建 Server.
Servlet 容器的核心功能主要有两个: 部署 Web 应用 和 将请求映射到具体的 Servlet 进行处理.
Tomcat 通过 org.apache.tomcat.util.http.mapper.Mapper 维护请求链接与 Host 、Context、Wrappe r 等Container 的映射。
同时,通过 org.apache.catalina.connector.MapperListener 监听器监听所有的 Host 、Context、Wrapper 组件,在相关组件启动、停止时注册或者移除相关映射。
此外,通过 org.apache.catalina.connector.CoyoteAdapter将Connector 与 Mapper、Container 联系起来。当 Connector 接收到请求后,首先读取请求数据,然后调用 CoyoteAdapter.service() 方法完成请求处理。
CoyoteAdapter.service 的具体处理过程如下(只列出主要步骤)。
链接器接收来自客户端的请求,并按照既定协议(如 HTTP)进行解析,然后交由 Servlet 容器处理。
与 HTTP/1.1 相比,HTTP/2.0 在传输方面进行了如下重要改进。
在 8.5 版本之前(8.0版本之后), Tomcat 同时支持 BIO、NIO、NIO2、APR 这 4 种 I/O 方式,其中 NIO2 为 8.0 版本新增。
自 8.5 版本开始,Tomcat 移除了对 BIO 的支持。
BIO 即阻塞式 IO,是 Java 提供的最基本的 I/O 方式。
在网络通信(此处主要讨论 TCP/IP 协议)中,需要通过 Socket 在客户端与服务端建立双向链接以实现通信,其主要步骤如下。
NIO2 是 JDK7 新增的文件及网络 IO 特性,它继承自 NIO,同时添加了众多特性及功能改进,其中最重要的即是对异步 IO (AIO)的支持。
APR ( Apache Portable Runtime ),即 Apache 可移植运行库。正如官网所言,APR 的使命是创建和维护一套软件库,以便在不同操作系统(Windows、Linux等)底层实现的基础上提供统一的 API。
set JAVA_OPTS=-server -Xms1024m -Xmx2048m -XX: PermSize=256m -XX:MaxPermSize=512m
需要添加到启动文件( catalina.bat/catalina.sh)的首行。
参数说明
Tomcat 服务器的配置主要集中于 $CATALINA_HOME/conf 下的 catalina.policy , catalina.properties、context.xml、 server.xml、tomcat-users.xml、web.xml 文件。
该文件主要用于 Catalina 容器启动阶段的配置,如服务器类加载器路径等.
server.xml 是 Tomcat 应用服务器的核心配置文件,它包括 Tomcat Servlet 容器(Catalina)的所有组件的配置,用于创建 Tomcat Servlet 容器。
Server
Service
Executor
Connector
Connector 用于创建链接器实例。默认情况下,server.xml配置了两个链接器,一个支持HTTP协议,一个支持AJP协议。因此大多数情况下,我们并不需要新增链接器配置,但是需要针对已有链接器进行优化。
一个简单的链接器配置如下:
< Connector port=""808o"protocol=“HTTP/1.1” connectionTimeout=“200oo” redirectPort="8443”/>
redirectPort: 如果当前Connector支持non-SSL请求,并且接收到一个请求,符合< security-constraint >约束,需要SSL传输,Catalina自动将请求重定向到此处指定的端口。
Engine
Host配置
Context配置
Context 用于配置一个 Web 应用,它支持的内嵌元素为:CookieProcessor、Loader、Manager、Realm、Resources、WatchedResource、JarScanner、Valve.
CookieProcessor 用于将 HTTP 请求中的 Cookie 头信息转换为 javax.servlet.http.Cookie 对象,或者将 Cookie 对象转换为 HTTP 响应中的 Cookie 头信息。如不指定,将默认使用 org.apache.tomcat.util.http.Rfc6265CookieProcessor。
Loader 用于配置当前 Context 对应的 Web 应用的类加载器。如不指定,将默认为 org.apache.catalina.loader. WebappLoader。
Manager 用于配置当前 Web 应用的会话管理器。如不指定,将默认为 org.apache.catalina.session.StandardManager。会话管理器存在独立启动和集群两种方式。
Resources 用于配置Web应用的有效资源(类文件、JAR 文件、HTML 等静态文件、JSP 等)。除非 Web 应用部分文件位于 Web 根目录之外,或存储于其他文件系统、数据库或者版本控制库,一般不需要额外添加资源,此时 Tomcat 会自动创建一个默认的文件系统,可以满足绝大多数的需要。
WatchedResource 用于配置自动加载文件检测。当指定文件发生更新时,Web 应用将会自动重新加载。对于每个 Web 应用, Tomcat 默认检测的文件是 WEB-INF/web.xml、SCATALINA_BASE/conf/web.xml。
JarScanner 用于配置 Web 应用 JAR 包以及目录扫描器, 扫描 Web 应用的 TLD 及 web-fragment.xml 文件. 如不配置,默认使用 org.apache.tomcat.util.scan.StandardJarScanner.
CookieProcessor
Loader
Loader 并不是一个 Java 类加载器,而是一个 Tomcat 组件,用于创建、加载以及销毁 Web 应用类加载器。它的生命周期管理与其他 Tomcat 组件一致。正因为如此,Web应用类加载器才会随着Web应用的状态而改变。
Tomcat 提供的默认实现为 org.apache.catalina.loader. webappLoader。大多数情况下,我们并不需要配置 Loader。但是在特殊情况下,Loader 配置可以使我们能够灵活控制 Java 类加载方式和顺序。
Manager配置
Resources
在 8.0 之前的版本中,Tomcat 通过< Resources >配置 Web 应用的静态资源,以实现类加载以及提供 HTML、JSP 或其他静态文件的访问服务。
Web部署描述文件的配置主要分为如下几类:
我们可以通过< context-param>添加 ServletContext 初始化参数,它配置了一个键值对.
我们可以使用它配置加载文件路径、应用运行状态(开发、测试、生产)以及日志等。其配置方式如下,可以同时配置多个初始化参数。
< context-param>
< description>The servletContext parameter description>
< param-name>name param-name>
< param-value>The parameter value param-value>
context-param>
< session-config>用于配置 Web 应用会话,包括超时时间、Cookie 配置以及会话追踪模式。
它将覆盖 server.xml 和 context.xml 中的配置。
< session-config>
< session-timeout>30 session-timeout>
< cookie-config>
< name>JSESSIONID name>
< domain>sample.myApp.com< / domain>
< path>/ path>
< comment>The session cookie< / comment>
< http-only>true http-only>
< secure>true secure>
< max-age>3600 max-age>
cookie-config>
< tracking-mode>COOKIE tracking-mode>
session-config>
< session-timeout>用于配置会话超时时间,单位为分钟。
< locale-encoding-mapping-list>用于指定本地化与响应编码的映射关系, 如果未显式地指明响应编码, 服务器将按照当前本地化信息确定响应编码。
< locale-encoding-mapping-list>
< locale-encoding-mapping>
< locale>zh locale>
< encoding>GBK encoding>
locale-encoding-mapping>
locale-encoding-mapping-list>
通过 web.xml 中的安全配置, 可以为 Web 应用增加页面访问权限。
Web 服务器
应用服务器
Web服务器拥有性能优势,可以支持负载均衡,
应用服务器可以提供各种技术组件用于系统开发构建,可以支持应用集群。
应用服务器对于静态资源的处理普遍性能相对较差,
而 Web 服务器则可以充分利用操作系统本地 IO 的优势。
同时,对于静态资源,Web 服务器可以通过缓存等各种方式来提高其访问性能。
本章首先简单介绍了一下 Web 服务器与应用服务器的区别,并列举了常见的几个需要 Web 服务器与应用服务器集成的场景。
可以使用 spring-session 来将会话缓存在 redis 中.
参考 https://blog.csdn.net/jsbylibo/article/details/106544932
移除 Tomcat 自带的几个 Web 应用, docs, examples, ROOT.
如果我们已经使用第三方工具来管理 Tomcat, 那么 host-manager 和 manager 可以直接移除.
如果我们希望使用这两个包,那么可以为它们增加IP访问限制(Remote-AddrValve,可以查看这两个应用下 META-INF/context.xml 文件中的内容。8.5 版本之前,需要手动开启,而 8.5 版本之后,则默认开启并只有本机可以访问)。
我们应当避免使用 root 用户权限启动 Tomcat (在 Linux 环境下),而应该单独为 Tomcat 服务器建立一个用户,并且授予运行应用服务器所需的最小系统权限,例如 Tomcat 用户不能远程访问 Linux 服务器.
移除不必要的组件
删除 AJP 链接器(8009).
如果我们不需要使用 host-manager 和 manager 管理 Tomcat, 可以将< Engine>下的< Realm>以及名为 “UserDatabase” 的 Resource 删除。
修改关键配置
修改 server.xml 中的 shutdown 监听端口和 SHUTDOWN 指令字符串.
如果不使用该功能,可以直接将其禁用(将 port 属性设置为-1 );
如果部署的 Web 应用仅允许有限的客户端访问(如一些管理型应用),此时可以通过 Remote-AddrValve 控制访问客户端 IP。
网络
内存/CPU
首先,可以通过 Windows 的任务管理器或者 Linux 的 top 命令查看服务器整体的资源使用情况。
如果我们仅仅希望查看服务器总体的 CPU、内存以及 I/O 读写情况,还可以使用 vmstat 命令.
幸运的是,对于基于 Java 的应用,JDK 在发布包中提供了内存及垃圾回收监控工具(位于$JAVA_HOME/bin)用于分析JVM的运行状况。
这些工具中,最常用的是 jstat 命令,它的命令格式如下:
jstat [ general0ption | outputoptions vmid [ interval[s|ms] [ count ] ]
除了 jstat,Java 还提供了 jmap 命令用于打印进程的堆内存详情、产生对象数量以及内存使用情况.
VisualVM 是一款 Java 应用监控以及故障排除的工具,它利用诸如 jvmstat、JMX、SA、AttachAPI 等技术获取运行数据,采用最快、最轻量级的技术以使被监控应用的开销降至最低。
数据库访问
首先,我们可以通过数据库自带的功能来查看 SQL 语句的执行情况,对于 Oracle 来说,可以通过 VSSQLAREA、VSSQLTEXT 两个视图来查看 SQL 语句的执行,如执行时间、读写情况等.
对于MySQL来说,它可以支持以日志的形式记录执行缓慢的SQL
其次,我们还可以通过一些工具,以非侵入的形式在应用级记录 SQL 日志,如 p6spy,下载地址为: https:/lgithub.com/p6spy/p6spy。
SpringBoot 项目中使用 Jetty servlet 容器替换 Tomcat 容器
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-tomcatartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jettyartifactId>
dependency>