一. Tomcat 体系架构
1. 什么是 Web 服务器?
其实并没有标准定义。一般认为,Web 服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,可以向浏览器等 Web 客户端提供文 档,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载什么是 Tomcat
2. 什么是 Tomcat
Tomcat 是一款开源轻量级 Web 应用服务器,是一款优秀的 Servlet 容器实现。
Servlet(Server Applet)是 Java Servlet 的简称,称为小服务程序或服务连接器,用 Java 编写的服务器端程序,具有独立于平台和协议的特性,主要 功能在于交互式地浏览和生成数据,生成动态 Web 内容。
Servlet 严格来讲是指 Java 语言实现的一个接口,一般情况下我们说的 Servlet 是指任何实现了这个 Servlet 接口的类。
实例化并调用 init()方法初始化该 Servlet,一般 Servlet 只初始化一次(只有一个对象)
service()(根据请求方法不同调用 doGet() 或者 doPost(),此外还有 doHead()、doPut()、doTrace()、doDelete()、doOptions()、destroy())。
当 Server 不再需要 Servlet 时(一般当 Server 关闭时),Server 调用 Servlet 的 destroy() 方法。
1. 典型的 Servlet 的处理流程
-
第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。 -
Servlet 容器在调用 service() 方法之前加载 Servlet。 -
然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。
3. Tomcat 版本介绍
**Servlet2.X:**项目目录结构必须要有 WEB-INF,web.xml 等文件夹和文件,在 web.xml 中配置 servlet,filter,listener,以 web.xml 为 java web 项目的统一 入口
servlet 3.x:项目中可以不需要 WEB-INF,web.xml 等文件夹和文件,在没有 web.xml 文件的情况下,通过注解实现 servlet,filter, listener 的声 明,当使用注解时,容器自动进行扫描。
同时 Tomcat8.5 进行了大量的代码重构,对比与 7.0 的版本,也符合 Tomcat 未来的代码架构体系。但是 Tomcat 的核心和主体架构还是一直保持不变。
1. 8.5 版本特点
支持 Servlet3.1
默认采用 NIO,移除 BIO
支持 NIO2(AIO)
支持 HTTP/2 协议
默认采用异步日志处理
太老的版本比如 6.0 的版本 Servlet 不支持 3 所以会导致部署 SpringBoot 等项目有问题,同时这个版本是在 9.0 出现以后发布的一个中间版本,主体架构延续 8.0,同时又实现了部分 9.0 的新特性。
4. Tomcat 启动
下载地址
https://tomcat.apache.org/download-80.cg
1. 一般启动
startup.bat/sh
# 或者
catalina.bat start
2. IDE 中启动
3. 嵌入式启动
SpringBoot 中一个 main 方法嵌入式启动 Tomcat
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
4. Debug 启动
在项目发布后,我们有时候需要对基于生产环境部署的应用进行调试,以解决在开发环境无法重现的 BUG。这时我们就需要用到应用服务器的远程 调试功能,这个主要是基于 JDK 提供的 JPDA(Java Platform Debugger Architecture,Java 平台调试体系结构)。不过一般情况下用不到。
使用 IDEA 远程部署 tomcat 和调试
- 在 catalina.sh 文件中加入以下的配置
CATALINA_OPTS="-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=192.168.1.134
-agentlib:jdwp=transport=dt_socket,address=15833,suspend=n,server=y"export CATALINA_OPTS
以上端口可以随意改动,但是必要的是后续的设置必须保持一致,并且务必保证端口没有被占用,这些设置的端口在防火墙中是开放 状态;
其中 1099 的是 tomcat 远程部署连接端口;
15833 是远程调试的端口;
192.168.19.200 是远程的服务器的 Ip
-
在 Linux 上启动 tomcat,使用命令启动 ./bin/catalina.sh run &
-
使用ide的远程连接
…
5. Tomcat 项目部署及目录结构
1. 项目部署
a. 隐式部署
直接丢文件夹、war、jar 到 webapps 目录,tomcat 会根据文件夹名称自动生成虚拟路径,简单,但是需要重启 Tomcat 服务器,包括要修改端口和访问路径的也需要重启。
如果部署页面没有权限怎么办
更具提示添加用户角色即可
tomcat-users.xml
<role rolename="manager-gui"/>
<role rolename="admin-gui"/>
<role rolename="manager-status"/>
<role rolename="manager-jmx"/>
<user username="admin" password="admin" roles="manager-gui,admin-gui,manager-status"/>
重启生效
b. 显式部署
添加 context 元素
server.xml 中的 Host 加入一个 Context(指定路径和文件地址),例如:
<Host name="localhost">
<Context path="/cat" docBase="D:\tomcat\cat.war" />
即/comet 这个虚拟路径映射到了 D:\work_tomcat\ref-comet 目录下(war 会解压成文件),修改完 servler.xml 需要重启 tomcat 服务器。
创建 xml 文件
在 conf/Catalina/localhost 中创建 xml 文件,访问路径为文件名,例如:
在 localhost 目录下新建 demo.xml,内容为:
<Context path="/cat" docBase="D:\tomcat\cat.war" />
不需要写 path,虚拟目录就是文件名 demo,path 默认为/demo,添加 demo.xml 不需要重启 tomcat 服务器。
对比: 三种方式比较
**隐式部署:**可以很快部署,需要人手动移动 Web 应用到 webapps 下,在实际操作中不是很人性化,不需要重启
server.xml中添加 context 元素 : 配置速度快,需要配置两个路径,如果 path 为空字符串,则为缺省配置,每次修改 server.xml 文件后都要重新启动 Tomcat 服务器,重新部署.
conf/Catalina/localhost下创建 xml 文件:服务器后台会自动部署,修改一次后台部署一次,不用重复启动 Tomcat 服务器,该方式显得更为智能化。
2. bin 执行脚本目录
startup 文件,主要是检查 catalina.bat/sh 执行所需环境,并调用 catalina.bat 批处理文件。启动 tomcat。
catalina 文件,真正启动 Tomcat 文件,可以在里面设置 jvm 参数。后面性能调优会重点讲
shutdown 文件,关闭 Tomcat
脚本 version.sh、startup.sh、shutdown.sh、configtest.sh 都是对 catalina.sh 的包装,内容大同小异,差异在于功能介绍和调用 catalina.sh 时的参数不同。
Version:查看当前 tomcat 的版本号,
Configtest:校验 tomcat 配置文件 server.xml 的格式、内容等是否合法、正确。
Service:安装 tomcat 服务,可用 net start tomcat 启动
3. conf 配置目录
0. web.xml
Tomcat 中所有应用默认的部署描述文件,主要定义了基础的 Servlet 和 MIME 映射(mime-mapping 文件类型,其实就是 Tomcat 处理的文件类型),如果 部署的应用中不包含 Web.xml,那么 Tomcat 将使用此文件初始化部署描述,反之,Tomcat 会在启动时将默认描述与定义描述配置进行合并。
加载一些 tomcat 内置的 servlet
DefaultServlet 默认的,加载静态文件 html,js,jpg 等静态文件。 (tomcat不合适处理静态文件,需要使用nginx,f5做静态分离)
JspServlet 专门处理 jsp。
1. 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"/>
<Connector port="8009" protocol="AJP/1.3" 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>
<Host name="www.hzg.com" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Context path="" docBase="/myweb1"/>
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="hzg_access_log" suffix=".txt" pattern="%h %l %u %t " %r" %s %b"/>
</Host>
</Engine>
</Service>
</Server>
Server是一个tomcat实例, 可以有多个Listener和多个Service,
一个Service有一个Engine和多个Connector
一个Engine可以有多个Host
一个Host可以有多个Context
Valve可以出现在各个组件里面
server.xml 中日志的 patter 解释
有效的日志格式模式可以参见下面内容,如下字符串,其对应的信息由指定的响应内容取代:
%a - 远程 IP 地址
%A - 本地 IP 地址
%b - 发送的字节数,不包括 HTTP 头,或“ - ”如果没有发送字节
%B - 发送的字节数,不包括 HTTP 头
%h - 远程主机名
%H - 请求协议
%l (小写的 L)- 远程逻辑从 identd 的用户名(总是返回’ - ')
%m - 请求方法
%p - 本地端口
%q - 查询字符串(在前面加上一个“?”如果它存在,否则是一个空字符串
%r - 第一行的要求
%s - 响应的 HTTP 状态代码
%S - 用户会话 ID
%t - 日期和时间,在通用日志格式
%u - 远程用户身份验证
%U - 请求的 URL 路径
%v - 本地服务器名
%D - 处理请求的时间(以毫秒为单位)
%T - 处理请求的时间(以秒为单位)
%I (大写的 i) - 当前请求的线程名称
2. context.xml
用于自定义所有 Web 应用均需要加载的 Context 配置,如果 Web 应用指定了自己的 context.xml,那么该文件的配置将被覆盖。
context.xml 与 server.xml 中配置 context 的区别
server.xml 是不可动态重加载的资源(Engine,Connector,Host启动时候就确定了),服务器一旦启动了以后,要修改这个文件,就得重启服务器才能重新加载。而 context.xml 文件(上下文可以切换)则不然,tomcat服务器会定时去扫描这个文件。一旦发现文件被修改(时间戳改变了),就会自动重新加载这个文件,而不需要重启服务器。
3. catalina.policy
权限相关 Permission ,Tomcat 是跑在 jvm 上的,所以有些默认的权限
4. tomcat-users.xml
配置 Tomcat 的 server 的 manager 信息
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
version="1.0">
<role rolename="manager-gui"/>
<role rolename="admin-gui"/>
<role rolename="manager-status"/>
<role rolename="manager-jmx"/>
<user username="admin" password="admin" roles="manager-gui,admin-gui,manager-status"/>
</tomcat-users>
5. logging.properties
设置 tomcat 日志
控制输出不输出内容到文件,不能阻止生成文件,阻止声文件可用注释掉
4. webapps 目录
存放 web 项目的目录,其中每个文件夹都是一个项目;如果这个目录下已经存在了目录,那么都是 tomcat 自带的。项目。其中 ROOT 是一个特殊的 项目,在地址栏中没有给出项目目录时,对应的就是 ROOT 项目。http://localhost:8080/examples,进入示例项目。其中 examples 就是项目名,即文件夹 的名字。
5. lib 目录
Tomcat 的类库,里面是一大堆 jar 文件。如果需要添加 Tomcat 依赖的 jar 文件,可以把它放到这个目录中,当然也可以把应用依赖的 jar 文件放到这 个目录中,这个目录中的 jar 所有项目都可以共享之,但这样你的应用放到其他 Tomcat 下时就不能再共享这个目录下的 Jar 包了,所以建议只把 Tomcat 需要的 Jar 包放到这个目录下;
6. work 目录
运行时生成的文件,最终运行的文件都在这里。通过 webapps 中的项目生成的!可以把这个目录下的内容删除,再次运行时会生再次生成 work 目录。 当客户端用户访问一个 JSP 文件时,Tomcat 会通过 JSP 生成 Java 文件,然后再编译 Java 文件生成 class 文件,生成的 java 和 class 文件都会存放到这个目 录下。
7. temp 目录
存放 Tomcat 的临时文件,这个目录下的东西可以在停止 Tomcat 后删除!
8. logs 目录
这个目录中都是日志文件,记录了 Tomcat 启动和关闭的信息,如果启动 Tomcat 时有错误,那么异常也会记录在日志文件中
localhost-xxx.log Web 应用的内部程序日志,建议保留
catalina-xxx.log
控制台日志host-manager.xxx.log
Tomcat 管理页面中的 host-manager 的操作日志,建议关闭
localhost_access_log_xxx.log 用户请求 Tomcat 的访问日志(这个文件在 conf/server.xml 里配置),建议关闭
conf 配置文件目录
6. Tomcat 组件及架构
Engine,Host,Context,Wrapper都被称为容器的组件
1. Server
Server 是最顶级的组件,它代表 Tomcat 的运行实例,它掌管着整个 Tomcat 的生死大权;
-
提供了监听器机制,用于在 Tomcat 整个生命周期中对不同时间进行处理 -
提供 Tomcat 容器全局的命名资源实现,JNDI -
监听某个端口以接受 SHUTDOWN 命令,用于关闭 Tomcat
主要是监听功能
2. Service
一个概念,一个 Service 维护多个 Connector 和一个 Container
3. Connector 组件
链接器:监听转换 Socket 请求,将请求交给 Container 处理,支持不同协议以及不同的 I/O 方式
就是我们socket编程中对应的socket.accept()方法对应的功能
4. Container
抽象出来的概念, 表示能够执行客户端请求并返回响应的一类对象,其中有不同级别的容器:Engine、Host、Context、Wrapper
5. Engine
整个 Servlet 引擎,最高级的容器对象, 一个Service只能有一个Engine
6. Host
表示 Servlet 引擎中的虚拟机,主要与域名有关,一个服务器有多个域名是可以使用多个 Host
7. Context
用于表示 ServletContext,一个 ServletContext 表示一个独立的 Web 应用, 主要和域名下的上下文路径关联, 所以一个域名可以有多个上下文路径
8. Wrapper
用于表示 Web 应用中定义的 Servlet
9. Executor
Tomcat 组件间可以共享的线程池
2. Tomcat 的核心组件
解耦:网络协议与容器的解耦。(容器只需和连接器打交道, 不用管使用的具体的通信协议, 连接器都会统一封装
即,我们熟知的Request 和Response对象)
Connector 链接器封装了底层的网络请求(Socket 请求及相应处理),提供了统一的接口,使 Container 容器与具体的请求协议以及 I/O 方式解耦。
Connector 将 Socket 输入转换成 Request 对象,交给 Container 容器进行处理,处理请求后,Container 通过 Connector 提供的 Response 对象将结果写入输出流。
因为无论是 Request 对象还是 Response 对象都没有实现 Servlet 规范对应的接口(这样多是不是为了让Connector和Serlvet解耦),Container 会将它们进一步分装成 ServletRequest 和 ServletResponse.
所以Connector和Servlet解耦, Container和Servlet耦合, 所以叫做Servlet容器, 而Connector不是
1. Tomcat 的链接器
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>
AJP 主要是用于 Web 服务器与 Tomcat 服务器集成,AJP 采用二进制传输可读性文本,使用保持持久性的 TCP 链接,使得 AJP 占用更少的带宽,并且链接开销要小得多,但是由于 AJP 采用持久化链接,因此有效的连接数较 HTTP 要更多。
HTTP2.0 目前市场不成熟。
对于 I/0 选择,要根据业务场景来定,一般高并发场景下,APR 和 NIO2 的性能要优于 NIO 和 BIO,(linux 操作系统支持的 NIO2 由于是一个假的,并没有真正实现 AIO(NIO2就是指的AIO),所以一般 linux 上推荐使用 NIO,如果是 APR 的话,需要安装 APR 库,而 Windows 上默认安装了),所以在 8.5 的版本中默认是 NIO。
|