Tomcat 模块
Tomcat 架构
- 连接器(Connector):处理 socket 连接,负责网络字节流与 Request 和 Response 对象的转化;
- 容器(Container):加载和管理 Servlet,以及具体处理 Request 请求;
在 Tomcat 框架中,连接器的实现是 Coyote,容器的实现是 Catalina
连接器 - Coyote
容器 - Catalina
- Catalina:负责解析 Tomcat 的配置文件,以此来创建服务器 Server 组件,并根据命令来对其进行管理;
- Server:服务器表示整个 Catalina Servlet 容器以及其他组件,负责组装并启动 Servlet 引擎,Tomcat 连接器。Server 通过实现 Lifecycle 接口,提供了一种优雅的启动和关闭整个系统的方式;
- Service:Service 是 Server 内部的组件,是 Tomcat 封装的对外提供完整的基于组件的 web 服务。一个 Server 包含多个 Service,各个 Service 之间是独立的,但是共享同一 JVM 资源。它将若干个 Connector 组件绑定到一个 Container(Engine)上对外提供服务;
- Connector:连接器,处理与客户端的通信,他负责接收客户请求,然后转给相关的容器处理,最后向客户返回响应结果;
Container:容器,负责处理用户的 Servlet 请求,并返回队形给 Web 用户的模块;
Container
Engine:表示整个 Catalina 的 Servlet 引擎,用来管理多个虚拟站点(Host),一个 Service 最多只能有一个 Engine,但是一个引擎可包含多个 Host;
- Host:代表一个虚拟主机或者说虚拟站点,负责 web 应用的部署和 Context 的创建。可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可包含多个 Context;
- Context:表示一个Web 应用程序,一个 Web 应用可包含多个 Wrapper;
Wrapper:最底层的容器,是对 Servlet 的封装,负责 Servlet 实例的创建、执行和销毁,Wrapper 作为容器中的最底层,不能包含子容器;
Tomcat 启动流程
加载 Tomcat 的配置文件,初始化容器组件,监听对应的端口号,接受客户端请求。Tomcat 请求处理流程
Pipeline 用于构建责任链,Valve 代表责任链上的每个处理器。
- Pipeline 中维护了一个基础的 Valve,它始终位于 Pipeline 的末端(最后执行),其封装了具体的请求处理和输出响应的过程。
- 我们可以调用 addValve() 方法,为 Pipeline 添加其他的 Valve,之后添加的 Valve 位于 基础的 Valve 之前,并按照添加顺序执行。
- Pipeline 通过获得首个 Valve 来启动整个责任链上处理器的执行。
Tomcat 服务器配置 —— server.xml
Tomcat 配置主要位于 tomcat/conf 目录下的 catalina.policy、cataline.properties、context.xml、server.xml、tomcat-user.xml、web.xml。
server.xml 是 Tomcat 服务器的核心配置文件,在 Tomcat 启动时会读取该文件配置,初始化具体的实例 。
详解:https://www.cnblogs.com/kismetv/p/7228274.html
Server
Server 是 server.xml 的根元素,用于创建一个 Server 实例,默认使用的实现类是 org.apache.cataline.core.StandardServer。
<Server port="8005" shutdown="SHUTDOWN">
</Server>
- port:Tomcat 监听的关闭服务器的端口;
- shutdown:关闭服务器的指令字符串;
Server 内嵌的子元素为 Listener、GlobalNamingResource、Service。
一、默认配置的 5 个 Listener:
<!-- 用于以日志形式输出服务器、操作系统、JVM的版本信息 -->
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- 用于加载(服务器启动)和销毁(服务器停止)ARP。如果找不到ARP库,会输出日志,不影响Tomcat启动 -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!-- 用于避免JRE内存泄露 -->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<!-- 用于加载(服务器启动)和销毁(服务器停止)全局命名服务 -->
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<!-- 用于在Context停止时重建Executor线程池中的线程,以避免ThreadLocal相关的内存泄露 -->
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
二、GlobalNamingResource 中定义了全局命名服务:
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
Service
一个 Tomcat Server 服务器,可以包含多个 Service 服务。一个 Service 代表我们部署在该服务器上的一个 Web 服务;
Service 元素用于创建 Service 实例,默认使用 org.apache.catalina.core.StandardService。默认情况下,Tomcat 仅指定了 Service 的名称,值为“Calalina”。
Service 可以内嵌的元素有 Listener、Executor、Connector、Engine:
- Listener:用于为 Service 添加声明周期监听器;
- Executor 用于配置 Service 的共享线程池;
- Connector 用于配置 Service 包含的连接器;
- Engine 用于配置 Service 中连接器的对应的 Servlet 容器引擎;
<Service name="Catalina"> </Service>
Executor
默认情况下,Service 并没有配置共享线程池。我们可以通过在Service
标签下配置Executor
来配置当前服务的共享线程池,通过在Connector
标签中指定共享线程池即可(下面介绍Connector
标签时会介绍)。
属性说明:<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxTheads="1000" minSpareThreads="100" maxIdleTime="60000" maxQueueSize="Integer.MAX_VALUE" prestartminSpareThreads="false" threadPriority="5" className="org.apache.catalina.core.StandardThreadExecutor"/>
- name:线程池名称,用于 Connector 中指定;
- namePrefix:线程池中线程的名称前缀,命名规则为 namePrefix+threadNumber;
- maxThreads:线程池的最大线程数;
- minSpareThreads:活跃线程数,即核心线程数,这些线程会一直存在不会被销毁;
- maxIdleTime:线程空闲时间,超过指定时间,活跃线程数之外的空闲线程会被销毁,默认为 6000(1分钟),单位毫秒;
- maxQueueSize:线程等待队列,默认为 int 的最大值;
- prestartminSpareThreads:启动线程池时是否预启动 minSpareThreads 指定的线程数,默认为 false,即不启动;
- threadPriority:线程池中线程优先级,默认值为 5,值从 1 到 10;
className:线程池的实现类,未指定情况下,默认实现类为 org.apache.catalina.core.StandardThreadExecutor。如果想使用自定义线程池首先需要实现 org.apache.catalina.Executor 接口;
Connector
Connector 元素用于创建连接器实例。在 9.x 版本中,默认会配置一个端口为 8080,协议为 HTTP 1.1 的连接器,用于监听端口号为 8080 的 Http 请求(之前版本还会有一个端口为 8009 的AJP 协议的连接器)。
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
属性说明:
port:端口号,用于连接器创建服务器 Socket 并进行监听,以等待客户端的请求。当该属性设置为 0,Tomcat 将会随机选择一个可用的端口号给当前 Connector 使用;
- protocol:当前 Connector 支持的访问协议。默认为 HTTP/1.1,并采用自动切换机制选择一个基于 Java NIO 的连接器或者基于 APR 的连接器(根据本地是否含有 Tomcat 的本地库判定);
如果不希望采用上述自动切换的机制,可以设置 protocol 属性下方值明确指定要使用的协议:
HTTP协议:
org.apache.coyote.http11.Http11NioProtocol: 非阻塞 Java NIO 连接器
org.apache.coyote.http11.Http11Nio2Protocol: 非阻塞 Java NIO2 连接器
org.apache.coyote.http11.Http11AprProtocol: APR连接器
AJP协议:
org.apache.coyote.ajp.AjpNioProtocol: 非阻塞 Java NIO 连接器
org.apache.coyote.ajp.AjpNio2Protocol: 非阻塞 Java NIO2 连接器
org.apache.coyote.ajp.AjpAprProtocol: APR 连接器
名词解释: HTTP/1.1、AJP、HTTP/2 属于应用层协议 NIO、APR、NIO2 是传输层 IO 模型
- executor:指定共享线程池的名称,也可以通过 maxThreads、minSpareThreads 等属性配置内部线程池;如果没指定,连接器 Connector 会有自己的线程池(默认为 10, 命名为 http-nio-8080-exec-num)
- connectionTimeOut:Connector 接收连接后的等待超时时间,单位为毫秒,-1 表示不超时;
- redirectPort:当前 Connector 不支持 SSL(HTTPS) 请求,接收到一个请求,并且也符合security-constraint 约束,需要 SSL 传输,Catalina 自动将请求重定向到指定的端口;
URIEncoding:用于指定 URI 的字符编码,Tomcat 8.x 版本默认的编码是 UTF-8;
Engine
Engine 作为 Servlet 引擎的顶级元素,内部可以嵌入 Host、Cluster、Listener、Realm、Valve;
<Engine name="Catalina" defaultHost="localhost"> </Engine>
name:用于指定 Engine 的名称,默认为 Catalina,该名称会影响一部分 Tomcat 的存储路径(如临时文件);
defaultHost:默认使用的虚拟主机名称,该项的值为标签 Host 中配置的 name 属性,当客户端请求指向的主机无效时,将交由默认的虚拟主机处理,默认为 localhost。如果指定的是 Host 中配置的域名,当访问 localhost 的时候就会指向 Host 的配置域名;
Host
Host 元素用于配置一个虚拟主机,内部可以嵌入 Alias、Cluster、Listener、Valve、Realm、Context。如果在 Engine 下配置了 Realm,那么此配置将在当前 Engine 下的所有 Host 共享。同样,如果在 Host 中配置 Realm,则在当前 Host 下的 Context 中共享。Context 中的 Realm 优先级 > Host 的 Realm 优先级 > Engine 中的 Realm 优先级。
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> </Host>
name:当前 Host 通用的网络名称,必须与 DNS 服务器上的注册信息一致。Engine 中包含的 Host name 必须存在一个与 Engine 的 defaultHost 设置一致的值。
- appBase:当前 Host 的应用基础目录,当前 Host 上部署的 Web 应用均在该目录下(可以是绝对目录、相对目录)。默认为 webapps;
- unpackWARs:设置为 true,Host 在启动时会将 appBase 中指定目录下的 war 包解压为目录;设置为 false,Host 将直接从 war 文件启动;
- autoDeploy:控制 tomcat 是否在运行时定期检测并自动部署新增或变更的 web 应用;
通过给 Host 添加别名,我们可以实现同一个 Host 拥有多个网络名称:
<Host name="www.web1.com" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Alias>www.web2.com</Alias>
</Host>
此时,我们就可以通过两个域名访问当前 Host 下的应用(需要确保 DNS 和 hosts 文件中添加的域名的映射配置)。
我们还可以配置多个 Host 虚拟主机,对应不同的应用路径,从而实现部署不同的应用:
<Host name="www.web1.com" appBase="webapps1"
unpackWARs="true" autoDeploy="true">
</Host>
<Host name="www.web2.com" appBase="webapps2"
unpackWARs="true" autoDeploy="true">
</Host>
此时,当我们访问 www.web1.com 的时候就会去 webapps1 下面找应用资源;访问 www.web2.com 的时候就会去 webapps2 下面找应用资源(需要确保 DNS 和 hosts 文件中添加的域名的映射配置)。
Context
Context 元素用于配置一个 Web 应用,默认配置如下:
<Context docBase="myApp" path="/myApp">
</Context>
- docBase:Web 应用目录获取 war 包的部署路径,可以是绝对路径,也可以是相对于 Host appBase 的路径;
- path:Web 应用的 Context 路口,如果我们 Host 名为 localhost,则 Web 应用访问的根路径为:http://localhost:8080/myApp;
Context 支持的内嵌元素有 CookieProcessor、Loader、Manager、Realm、Resource、WatchedResource、JarScanner、Valve;
默认情况下,server.xml 中并没有对 Context 的配置,这是因为 Tomcat 开启了自动部署,Web 应用由 Tomcat 通过特定的规则自动部署。
自动部署场景下,Tomcat 会自动扫描 appBase 中的 war 包和应用目录,docBase 只有不再 appBase中才需要指定,而 path 属性值则直接根据 appBase 的 war 名称或应用目录名称自动推导出来。
总结
当请求被发送到 Tomcat 所在的主机时,如何确定哪个 Web 应用来处理这个请求呢?
- 根据协议和端口号确定 Service 的 Connector,从而确定了 Engine 容器来处理;
- 根据域名或 IP 确定 Host;
- 根据 URI 上下文确定 Context/Web 应用;
- 根据 URI 请求路径确定是哪个 Servlet 处理该请求;
例如:当请求 http://localhost:8080/app1/index.html 时,首先通过协议(http)和端口号(8080)确定 Service;然后通过主机名(localhost)确定 Host;最后通过 URL 上下文(app1)确定 Web 应用目录 app1;最后根据 URL 请求路径(index.html)确定 Servlet;
Web 应用配置 —— web.xml
web.xml 是 web 应用的描述文件,它支持的元素及属性来自于 Servlet 规范定义。在 Tomcat 中,Web 应用的描述信息包括 tomcat/conf/web.xml 中默认配置以及 Web 应用 WEB-INF/web.xml 下的定制配置。
ServletContext 初始化参数
我们可以通过添加 ServletContext 初始化参数,它配置了一个键值对,这样我们可以在应用程序中使用 javax.servlet.ServletContext.getInitParameter()方法获取参数。
配置初始化参数:
<context‐param>
<param‐name>contextConfigLocation</param‐name>
<param‐value>classpath:applicationContext‐*.xml</param‐value>
<description>Spring Config File Location</description>
</context‐param>
获取初始化参数:
HttpServletRequest.getServletContext().getInitParameter("contextConfigLocation");
会话配置
用于配置 Web 应用会话,包括超时时间、Cookie 配置以及会话追踪模式。它将覆盖 server.xml 和 context.xml 中的配置。
<session‐config>
<session‐timeout>30</session‐timeout>
<cookie‐config>
<name>JSESSIONID</name>
<domain>localhost</domain>
<path>/</path>
<comment>Session Cookie</comment>
<http‐only>true</http‐only>
<secure>false</secure>
<max‐age>3600</max‐age>
</cookie‐config>
<tracking‐mode>COOKIE</tracking‐mode>
</session‐config>
- session‐timeout:会话超时时间,单位分钟
- cookie‐config:用于配置会话追踪 Cookie
- name:Cookie 的名称
- domain:Cookie 的域名
- path:Cookie 的路径
- comment:注释
- http‐only:cookie 只能通过 HTTP 方式进行访问,JS 无法读取或修改,此项可以增加网站访问的安全性。
- secure:此 cookie 只能通过 HTTPS 连接传递到服务器,而 HTTP 连接则不会传递该信息。注意是从浏览器传递到服务器,服务器端的 Cookie 对象不受此项影响。
- max‐age:以秒为单位表示 cookie 的生存期,默认为 ‐1 表示是会话 Cookie 在浏览器关闭时就会消失。
- tracking‐mode:用于配置会话追踪模式,Servlet3.0 版本中支持的追踪模式:COOKIE、URL、SSL
- COOKIE : 通过 HTTP Cookie 追踪会话是最常用的会话追踪机制, 而且 Servlet 规范也要求所有的 Servlet 规范都需要支持 Cookie 追踪。
- URL : URL 重写是最基本的会话追踪机制。当客户端不支持 Cookie 时,可以采用 URL 重写的方式。当采用 URL 追踪模式时,请求路径需要包含会话标识信息,Servlet 容器会根据路径中的会话标识设置请求的会话信息。如:http://www.myserver.com/user/index.html;jessionid=1234567890。
- SSL : 对于 SSL 请求, 通过 SSL 会话标识确定请求会话标识。
Servlet
Servlet 的配置主要是两部分, servlet 和 servlet-mapping: ```xmlmyServlet cn.zsy.web.MyServlet fileName init.conf 1 true
1. servlet‐name : 指定 servlet 的名称, 该属性在 web.xml 中唯一。
1. servlet‐class : 用于指定 servlet 全限定类名;
1. init‐param: 用于指定 servlet 的初始化参数, 在应用中可以通过 HttpServlet.getInitParameter 获取。
1. load‐on‐startup: 用于控制在 Web 应用启动时,Servlet 的加载顺序。 值小于 0,web 应用启动时,不加载该 servlet, 第一次访问时加载。
1. enabled: true,false。若为 false,表示 Servlet 不处理任何请求。
1. url‐pattern: 用于指定 URL 表达式,一个 servlet‐mapping 可以同时配置多个 url‐pattern。
Servlet 文件上传配置
```xml
<servlet>
<servlet‐name>uploadServlet</servlet‐name>
<servlet‐class>cn.zsy.web.UploadServlet</servlet‐class>
<multipart‐config>
<location>C://path</location>
<max‐file‐size>10485760</max‐file‐size>
<max‐request‐size>10485760</max‐request‐size>
<file‐size‐threshold>0</file‐size‐threshold>
</multipart‐config>
</servlet>
- location:存放生成的文件地址。
- max‐file‐size:允许上传的文件最大值。默认值为 ‐1,表示没有限制。
- max‐request‐size:针对该 multi/form‐data 请求的最大数量,默认值为 ‐1,表示无限制。
- file‐size‐threshold:当数量量大于该值时,内容会被写入文件。
Listener
Listener 用于监听 servlet 中的事件,例如 context、request、session 对象的创建、修改、删除,并触发响应事件。Listener 是观察者模式的实现,在 servlet 中主要用于对 context、request、session对象的生命周期进行监控。在 servlet2.5 规范中共定义了 8 种 Listener。在启动时,ServletContextListener 的执行顺序与 web.xml 中的配置顺序一致,停止时执行顺序相反。<listener> <listener‐class>org.springframework.web.context.ContextLoaderListener</listener‐class> </listener>
Filter
Filter 用于配置 web 应用过滤器,用来过滤资源请求及响应。经常用于认证、日志、加密、数据转换等操作,配置如下: ```xmlmyFilter cn.zsy.web.MyFilter true
language
CN
1. filter‐name:用于指定过滤器名称,在 web.xml 中,过滤器名称必须唯一。
1. filter‐class:过滤器的全限定类名, 该类必须实现 Filter 接口。
1. async‐supported:该过滤器是否支持异步
1. init‐param:用于配置 Filter 的初始化参数,可以配置多个,可以通过 FilterConfig.getInitParameter 获取
1. url‐pattern:指定该过滤器需要拦截的URL。
<a name="GEskx"></a>
# JVM 配置
最常见的 JVM 配置当属内存分配,因为在绝大多数情况下,JVM 默认分配的内存可能不能够满足我们的需求,特别是在生产环境,此时需要手动修改 Tomcat 启动时的内存参数分配。
Windows 环境修改 bin/catalina.bat
```bash
set JAVA_OPTS=‐server ‐Xms2048m ‐Xmx2048m ‐XX:MetaspaceSize=256m
‐XX:MaxMetaspaceSize=256m ‐XX:SurvivorRatio=8
Linux 环境修改 bin/catalina.sh
JAVA_OPTS="‐server ‐Xms1024m ‐Xmx2048m ‐XX:MetaspaceSize=256m
‐XX:MaxMetaspaceSize=512m ‐XX:SurvivorRatio=8"
- -Xms:堆内存的初始大小;
- -Xmx:堆内存的最大大小;
- -Xmn:新生代的内存大小,官方建议是整个堆内存的 3/8;
- -XX:MetaspaceSize:元空间内存初始大小,在 JDK1.8 版本之前配置为 -XX:PermSize(永久代);
- -XX:MaxMetaspaceSize:元空间内存最大大小;
- -XX:InitialCodeCacheSize/-XX:ReservedCodeCacheSize:代码缓存区大小;
- -XX:NewRatio:设置新生代和老年代的相对大小比例,这种方式的优点是新生代会随着整个堆大小动态扩展。如 -XX:NewRatio=3 指定老年代/新生代为 3/1,老年代占堆大小的 3/4,新生代占 1/4;
- -XX:SurvivorRatio:指定伊甸园区 (Eden) 与幸存区大小比例。例如 -XX:SurvivorRatio=10 表示伊甸园区(Eden)是幸存区 To 大小的 10 倍 (也是幸存区 From 的 10 倍)。 所以,伊甸园区(Eden)占新生代大小的 10/12,幸存区 From 和幸存区 To 每个占新生代的 1/12 。注意,两个幸存区永远是一样大的。
Tomcat 性能优化
配置调优
通过调整 tomcat/conf/server.xml 中关于连接器的配置可以提升应用服务器的性能:
- maxConnections:最大连接处理数,当达到该值后,服务器接收但不会处理更多的请求,额外的请求将会阻塞知道连接数低于 maxConnections。可以通过
ulimit -a
查看服务器限制。 - maxThreads:最大线程数;
- acceptCount:最大排队等待数,当服务器接收的请求数量达到 maxConnections,此时 Tomcat 会将后面的请求,存放在任务队列中进行排序,acceptCount 指的是任务队列中排队等待的请求数。一台 Tomcat 的最大请求处理数量,是 maxConnections + acceptCount;
资料
Tomcat 专题.pdf
Tomcat 专题_2.pdf