一,浏览器访问服务的简略流程
从图中可以知道,当用户发起http请求后,客户端与服务器会通过三次握手建立连接,并发送http请求数据包到tomcat,经过一系列流程处理之后,tomcat返回响应数据包到浏览器,浏览器渲染并呈现给用户。
那么tomcat到底是如何处理来自客户端等请求并响应的呢
二,tomcat组件解释
图中tomcat核心组件分别是连接器Connector和容器Container
- 连接器负责对外交流,处理socket请求,读取字节流解析成tomcat request和response对象。
- 容器负责内部业务逻辑,管理servlet的生命周期,处理具体业务请求逻辑。
Coyote组件
Coyote是Tomcat中连接器组件的名称,从图中可以知道它内部由EndPoint,Processor,Adapter
三个核心组件构成,下面来看下这三个组件分别是做什么的。
- EndPoint
EndPoint是Coyote通信监听接口,是具体的Socket接收发送处理器,是用来实现TCP/IP协议的,是对传输层的抽象。
- Processor
Processor是Coyote协议处理接口,用来接收EndPoint的Socket,读取字节流解析成Tomcat Request和Response对象,并通过Adapter提交到对应容器处理,是用来实现HTTP协议的,是对应用层的抽象。
- ProtocolHandler
Coyote 协议接口,通过Endpoint和Processor组件,实现针对具体协议的处理能力。Tomcat 按照协议和I/O 提供了6个实现类 : AjpNioProtocol,AjpAprProtocol,AjpNio2Protocol,Http11NioProtocol,Http11Nio2Protocol,Http11AprProtocol
- Adapter
由于协议不同,客户端发过来的请求信息格式也不相同。ProtocolHandler接口解析请求并生成Tomcat Request类。由于不同协议导致的Request差异,Tomcat设计者的解决方案是引入CoyoteAdapter,这是适配器模式的经典运用,连接器调用CoyoteAdapter的Sevice方法,传入Tomcat Request对象, CoyoteAdapter负责将Tomcat Request转成ServletRequest,再调用容器。
从上面的分析可以看出来Coyote负责的是具体协议(应用层)和IO(传输层)相关内容,将请求封装成tomcat request并通过adapter转换成servlet request再发送到servlet容器,实现http服务与业务逻辑的解耦。
Catalina组件
而Catalina是Tomcat的 servlet容器。
Catalina是Tomcat的servlet容器,Tomcat本质上就是一款Servlet 容器,因为Catalina才是Tomcat的核心,其他模块都是为Catalina提供支撑的。接下来来看下图中Catalina的组成部分分别都是干什么的。
- Engine
表示整个Catalina的Servlet引擎,用来管理多个虚拟站点,一个Service最多只能有一个Engine, 但是一个Engine可包含多个Host。
- Host
代表一个虚拟主机,可以给Tomcat配置多个虚拟主机地址,而一个虚拟主机下可包含多个Context.
- Context
表示一个Web应用程序, 一个Web应用可包含多个Wrapper
- Wrapper
表示一个Servlet,Wrapper 作为容器中的最底层,不能包含子容器
Jasper组件
提供JSP引擎,用于解析处理jsp格式文件。
Juli组件
提供日志服务
Naming组件
提供JNDI服务
三,怎么配置tomcat容器
Tomcat作为服务器的配置,主要在conf目录下的server.xml 文件,server.xml中包含了 Servlet容器的相关配置,即Catalina的配置。先来看下server.xml的具体内容。
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<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 name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
server 标签
- port:关闭服务器的监听端口
- shutdown:关闭服务器的指令字符串
<Server port="8005" shutdown="SHUTDOWN">
<!--以日志形式输出服务器,操作系统,jvm的版本信息-->
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- 加载(服务器启动) 和 销毁 (服务器停止)APR。如果找不到APR库,则会输出日志,并不影响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" />
<GlobalNamingResources>
<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>
......
</Server>
service 标签
该标签用于创建 Service 实例,默认使用 org.apache.catalina.core.StandardService
- name:服务名称
<Service name="Catalina">
......
</Service>
Executor标签
- name:线程池名称
- namePrefix:线程名前缀
- maxThreads:最大线程数
- minSpareThreads:核心线程数(空闲时不会被回收)
- maxQueueSize:队列大小(大于最大线程数的请求会被放到队列排队)
- prestartminSpareThreads:启动线程池时是否启动minSpareThreads部分线程。默认值为false,即不启动.
- threadPriority:线程池中线程优先级,默认值为5,值从1到10
- className:线程池实现类,未指定情况下,默认实现类为org.apache.catalina.core.StandardThreadExecutor。如果想使用自定义线程池首先需要实现org.apache.catalina.Executor接口
<Executor name="xialuThreadPool"
namePrefix="thread-exec-"
maxThreads="200"
minSpareThreads="100"
maxIdleTime="60000"
maxQueueSize="Integer.MAX_VALUE"
prestartminSpareThreads="false"
threadPriority="5"
className="org.apache.catalina.core.StandardThreadExecutor"/>
Connector 标签
- prot:端口号,connector用于创建服务socket并进行监听,如果端口号设置为0,tomcat会随机选择一个可用端口号给当前connector
- protocol:当前connector支持的访问协议,默认为HTTP/1.1,并采用自动切换机制选择一个机遇java nio的链接7⃣️或者基于本地的APR链接器
- connectionTimeout: Connector收到连接后的等待超时时间,单位毫秒,-1表示不超时。
- redirectPort:当前connector不支持ssl请求,收到https请求之后,会重定向到redirectPort配置的端口
- executor:指定共享线程池的名称
- URIEncoding:指定编码uri的字符串编码,tomcat8.x版本默认编码为utf-8,tomcat7.x版本默认为iso-8859-1
<Connector port="8080"
protocol="HTTP/1.1"
executor="commonThreadPool"
maxThreads="1000"
minSpareThreads="100"
acceptCount="1000"
maxConnections="1000"
connectionTimeout="20000"
compression="on"
compressionMinSize="2048"
disableUploadTimeout="true"
redirectPort="8443"
URIEncoding="UTF-8" />
Engine 标签
- name: 用于指定Engine的名称,默认为Catalina
- defaultHost:默认使用的虚拟主机名称, 当客户端请求指向的主机无效时, 将交由默认的虚拟主机处理, 默认为localhost
<Engine name="Catalina" defaultHost="localhost">
.....
</Engine>
Host 标签
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
......
</Host>
context 标签
- docBase:Web应用目录或者War包的部署路径。可以是绝对路径,也可以是相对于Host appBase的相对路径。
- path:Web应用的Context 路径。如果我们Host名为localhost,则该web应用访问的根路径为:http://localhost:8080/web_demo。
<Host name="www.xialu.com" appBase="webapps" unpackWARs="true"
autoDeploy="true">
<Context docBase="/Users/yingdian/web_demo" path="/web3"></Context>
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>