Tomcat 系列
Tomcat 系列
一. 基本概念
1.1 java jdk 概念
##背景知识
无论是何种程序,要能在计算机上运行,必须能转换为二进制的机器语言才能和硬件进行交互,在机器语言的上层是汇编语言,再上层是C/C++这样较底层的语言,由于它们严重依赖于平台架构,所有一般只能运行在程序源代码已编译的机器上,可移植性比较差。
##java简介
Java是一种面向对象的语言,它的层次比C更高一点,层次指的是离硬件更远一点。它将写好的程序文件(.java)通过java编译器javac编译成字节码类型的class文件(.class),在编译过程中涉及词法分析、语法分析、语义分析、字节码生成等过程,最终生成字节码的 class文件。class文件是Java的类文件,是编译成功后的字节码文件,字节码由Java虚拟机JVM解释执行,它将每一条字节码送给解释器,再翻译成机器语言,从而在特定的机器上运行。Java通过JVM的方式实现了一次编译到处运行的功能。
即: 源码XXX.java-->javac编译器-->字节码XXX.class-->JVM-->机器语言(依赖于不同平台)-->执行
JRE(Java Runtime Environment)是包含了JVM和其他一些简单功能的JAVA运行环境,它适用于只运行java程序时。
JDK(Java Development Kit)比JRE包含了更多东西,它除了能作为JAVA运行环境,还提供了很多用于开发的工具,所以它适用于开发程序时使用。
JAVA SE是java开发标准版,里面有JDK,Java EE是企业版,本质上ee只是比se多提供了几个类库而已。
1.2 jsp、servlet是什么
#发展历史 applet
在web应用程序上,早期Java的实现方式是服务器端放置应用程序,客户端访问时将其下载到客户端本地并执行,这样不仅不安全,而且要求客户有java运行环境,这种实现方式是applet。
#02 servlet
与applet相对的是servlet,但它是服务端程序。后来,java将应用程序放在服务器端,客户端请求此应用程序时,服务端通过servlet类库分析http协议,将请求的应用程序在服务端执行,然后将结果组织起来返回给客户端,但此时servlet能分析的http协议非常简单,且和html的组织方式非常不友好,它要求java程序员首先得懂html开发(实际上现在还是如此,java程序员至少要懂简单的html/css/javascript等前端技术),
于是后来出现了JSP类库。
#03 JSP介绍
JSP可以简单的将java代码嵌入在html文档中,它们能够很友好地结合,结合后的文档类型为.jsp文件。当客户端请求应用程序资源时,
JSP类库负责解析.jsp文件中的jsp部分并通过jasper组件将其翻译成servlet的java源代码,然后再编译成class文件并交给JVM来执行。
实际上,jsp的本就就是servlet,jsp类只不过是继承于servlet类并添加了一些和html友好结合的特性,最终它还是要翻译成servlet代码。
JSP的本质还是Servlet,每个JSP页面就是一个Servlet对象(当然也可能引用了其他servlet对象),Servlet再负责响应用户的动态请求数据(其实也包括静态数据,因为jasper翻译jsp代码时,静态标签也被翻译到servlet的java源文件中以待输出)。对于Tomcat而言,JSP页面生成的Servlet放在work路径对应的Web应用下。
考虑到tomcat和httpd、nginx等http服务程序的对比,有两点需要明确:
(1).一个java程序只有一个进程,但是可以有多个线程,也就是说java程序的开发是基于线程的。那唯一的进程就是JVM进程,每个应用程序都开启一个JVM进程,根据开发时设计的多线程代码,在这个JVM进程中会启动多个线程。它不像httpd或nginx,能开启多进程(对于tomcat而言,这意味着多个不同的应用程序甚至意味着开启多个tomcat实例)。
(2).tomcat可以处理动态请求,也可以处理静态资源请求。但无论是动态资源,还是静态资源的请求,都是经过servlet处理并响应给客户端的,只不过请求静态资源时使用的是默认的servlet。虽然它能像httpd和nginx一样处理静态资源,但显然,它既要处理动态请求,又要处理静态请求,压力会很大。因此tomcat前一般使用httpd或nginx专门处理静态请求,而动态请求则通过反向代理的方式代理至tomcat。
1.3 web服务器、web容器、应用程序服务器
web服务器用于提供web服务,要求能解析http协议,通常认为提供静态内容的服务器是web服务器。如apache httpd、nginx等。
对于java而言,web容器是能提供servlet容器的服务器,它们是等价的概念。常见的有tomcat、weblogic、websphere、jboss。其中tomcat只提供servlet容器,它们在功能上是等价的。除tomcat外,后面3种web容器还提供除servlet容器外的EJB容器,专用于大型分布式程序开发。
应用程序服务器是用于提供应用服务的服务器。这是业务逻辑上的概念划分。更具体一点的说,它提供WEB容器(servlet容器)、EJB容器以及其他功能。
它们之间的关系和功能大致如下:
web服务器提供web服务,主要处理http请求并响应给客户端,并可以将动态请求委托给其他程序,如cgi脚本、jsp脚本、asp脚本等进行处理;
web容器即servlet容器主要负责处理基于http请求的动态jsp内容;
EJB容器主要提供和后端数据库服务、其他服务进行交互的功能;
应用服务器通常来说包括servlet容器或EJB容器,它们都运行于支持Java的应用服务器中,因此tomcat/weblogic/websphere/jboss都算是应用服务器。
1.4 tomcat体系结构
#01 体系结构
tomcat是jdk+servlet(严格地说是+jsp)实现的精简版的java ee,由于它只在jdk的基础上附加了jsp和servlet类库,所以它的应用范围主要是web应用。tomcat项目目前由apache软件基金会维护。
它是一种应用程序服务器,只提供servlet容器,同时还提供apache解析静态HTML,只不过之它的处理能力不如独立的apache服务器。类似的应用程序服务还有websphere/weblogic/jetty/resin/jboss等,它们都是在jdk基础上附加各种类库实现不同程度的java ee(tomcat=jdk+servlet)。
对于tomcat来说,它高度模块化,通过各个组件实现各种功能。它的体系结构如下图所示:
- 图示

- server是顶级类,一个server算是一个tomcat实例,在此层次中可定义tomcat服务的监听端口。
- service是server下的子组件,用于封装绑定connector和containor,并为它们提供一个名称属性。有了service就可以提供相关的服务,如监听TCP连接请求、处理http请求。注意server是管理整个tomcat实例的层次,它和提供服务没有关系。
- connector是连接器,定义http协议(默认)以及该协议的监听端口。连接器用于接收客户端请求并将containor处理的数据返回给客户端。
- containor称为容器,它和connector连接器进行绑定。该容器内有4个子容器,包括:engine容器、host容器、context容器、Wrapper容器。容器用于分析、处理请求,并构建响应给connector以发送给客户端。它和connector是tomcat的心脏组件。
- engine容器定义servlet引擎,用于定义引擎的名称、默认的虚拟主机。引擎用于分析http请求并将请求转发给对应的虚拟主机。
- host容器用于定义虚拟主机 域名IP等。
- context容器用于定义webapp,一个context定义一个webapp。它是真正管理servlet容器的层次。
- wrapper容器对应的是真正的servlet容器,一个wrapper代表一个servlet,它负责管理一个Servlet,包括的Servlet的装载、初始化、执行以及资源回收。Wrapper是最底层的容器,一个context只能包含一个wrapper。在配置文件中,无法配置该容器的属性。
还有一些其他组件,如session管理组件、JMX等。
一个server可以有多个service。一个service可以有多个connector和唯一的containor。containor是容器类,从containor层次开始,真正进入servlet容器相关的过程。它包含了唯一的engine容器,engine容器中包含了一个或多个host容器,host容器中包含了一个或多个context容器,context容器中包含了唯一的wrapper。它们的组织结构大致如下:
<server>
<service>
<connector />
<engine>
<host>
<context />
<context />
</host>
<host>
<context />
</host>
</engine>
</service>
<service>
......
</service>
</server>
二.安装
2.1 java 环境安装
#Tomcat 9 需要 Java 8 以上的環境,而 CentOS 7 官方的套件庫就有收錄 Java 8,所以用 yum 安裝即可
#01 开始安装
yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel
#02 检查版本
java -version
[root@cx_test_001 ~]# java -version
openjdk version "1.8.0_372"
OpenJDK Runtime Environment (build 1.8.0_372-b07)
OpenJDK 64-Bit Server VM (build 25.372-b07, mixed mode)
2.2 安装tomcat
#01 安装tomcat 9版本
cd /opt/
wget --no-check-certificate https://downloads.apache.org/tomcat/tomcat-9/v9.0.79/bin/apache-tomcat-9.0.79.tar.gz
#02 下载sha512校验码
wget --no-check-certificate https://downloads.apache.org/tomcat/tomcat-9/v9.0.79/bin/apache-tomcat-9.0.79.tar.gz.sha512
#03 检查两码是否相同
[root@cx_test_001 opt]# sha512sum apache-tomcat-9.0.79.tar.gz
7a0d99b5fc37c9e9ac26b554fab9147ce0a2ba59fad41e2565b15e9f6e137bf0105f5c9cd6b7b508837ff24feb7b95b2aba49e0abc7b1480a30a11606e79802a apache-tomcat-9.0.79.tar.gz
[root@cx_test_001 opt]# cat apache-tomcat-9.0.79.tar.gz.sha512
7a0d99b5fc37c9e9ac26b554fab9147ce0a2ba59fad41e2565b15e9f6e137bf0105f5c9cd6b7b508837ff24feb7b95b2aba49e0abc7b1480a30a11606e79802a *apache-tomcat-9.0.79.tar.gz
#04 解压
tar xf apache-tomcat-9.0.79.tar.gz
mv apache-tomcat-9.0.79 tomcat
2.3 配置systems 启动指令
#01 创建systemd文件
cat <<EOT >/etc/systemd/system/tomcat.service
[Unit]
Description=Apache Tomcat 9
After=syslog.target network.target
[Service]
User=root
Group=root
Type=forking
Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid
Environment=CATALINA_HOME=/opt/tomcat
Environment=CATALINA_BASE=/opt/tomcat
ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh
Restart=on-failure
Environment='CATALINA_OPTS=-Xms512M -Xmx8192M -server -XX:+UseParallelGC'
Environment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom'
[Install]
WantedBy=multi-user.target
EOT
#02 重载systemd
systemctl daemon-reload
2.3 启动tomcat
##检查环境变量
[root@zw_mysql bin]# ./version.sh
Using CATALINA_BASE: /opt/tomcat
Using CATALINA_HOME: /opt/tomcat
Using CATALINA_TMPDIR: /opt/tomcat/temp
Using JRE_HOME: /usr/local/jdk1.8.0_161
Using CLASSPATH: /opt/tomcat/bin/bootstrap.jar:/opt/tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:
Server version: Apache Tomcat/9.0.79
Server built: Aug 8 2023 20:41:26 UTC
Server number: 9.0.79.0
OS Name: Linux
OS Version: 3.10.0-1160.el7.x86_64
Architecture: amd64
JVM Version: 1.8.0_161-b12
JVM Vendor: Oracle Corporation
#01 启动tomcat
systemctl start tomcat
#02 检查状态
systemctl status tomcat
● tomcat.service - Apache Tomcat 9
Loaded: loaded (/etc/systemd/system/tomcat.service; disabled; vendor preset: disabled)
Active: active (running) since 三 2023-08-23 11:04:31 CST; 8s ago
Process: 2614 ExecStart=/opt/tomcat/bin/startup.sh (code=exited, status=0/SUCCESS)
Main PID: 2627 (java)
Tasks: 32
Memory: 132.2M
CGroup: /system.slice/tomcat.service
└─2627 /usr/bin/java -Djava.util.logging.config.file=/opt/tomcat/conf/logging.properties -Djava.util.loggi...
8月 23 11:04:31 zw_mysql systemd[1]: Starting Apache Tomcat 9...
8月 23 11:04:31 zw_mysql startup.sh[2614]: Tomcat started.
8月 23 11:04:31 zw_mysql systemd[1]: Started Apache Tomcat 9.

三. 配置文件介绍
3.1目录结构
#01 配置文件列表
[root@zw_mysql jsp]# ll /opt/tomcat/
[root@zw_mysql tomcat]# ll -d */
drwxr-x--- 2 root root 4096 8月 23 11:04 bin/
drwx------ 3 root root 254 8月 23 11:44 conf/
drwxr-x--- 2 root root 4096 8月 23 11:04 lib/
drwxr-x--- 2 root root 197 8月 23 11:04 logs/
drwxr-x--- 2 root root 48 8月 23 11:44 temp/
drwxr-x--- 7 root root 81 8月 9 04:41 webapps/
drwxr-x--- 3 root root 22 8月 23 11:04 work/
logs #目录是日志目录
temp #是临时目录
webapps #是存放web程序的根目录
work #目录是存放编译后生成的class文件的目录
bin #目录下有很多脚本文件,有.sh脚本,也有.bat脚本
3.2 bin
#01 命令目录下所有文件
[root@zw_mysql bin]# ls *.sh -l
-rwxr-x--- 1 root root 25323 8月 9 04:41 catalina.sh
-rwxr-x--- 1 root root 1997 8月 9 04:41 ciphers.sh
-rwxr-x--- 1 root root 1922 8月 9 04:41 configtest.sh
-rwxr-x--- 1 root root 9100 8月 9 04:41 daemon.sh
-rwxr-x--- 1 root root 1965 8月 9 04:41 digest.sh
-rwxr-x--- 1 root root 3382 8月 9 04:41 makebase.sh
-rwxr-x--- 1 root root 4317 8月 9 04:41 setclasspath.sh
-rwxr-x--- 1 root root 1902 8月 9 04:41 shutdown.sh
-rwxr-x--- 1 root root 1904 8月 9 04:41 startup.sh
-rwxr-x--- 1 root root 5540 8月 9 04:41 tool-wrapper.sh
-rwxr-x--- 1 root root 1908 8月 9 04:41 version.sh
解释下:
catalina.sh #类似于System服务管理脚本,支持stop、start和configtest,但不支持restart和reload
例如: catalina.sh start
catalina.sh stop
startup.sh 等价于 catalina.sh start #开启
shudown.sh 等价于 catalina.sh stop #关闭
configtest.sh 等价于 catalina.sh configtest #检查语法
3.2 conf
#01 在安装目录下的conf目录下有几个配置xml格式的配置文件
[root@zw_mysql tomcat]# ls conf/*.xml -l
-rw------- 1 root root 1400 8月 9 04:41 conf/context.xml
-rw------- 1 root root 1149 8月 9 04:41 conf/jaspic-providers.xml
-rw------- 1 root root 7931 8月 23 11:36 conf/server.xml
-rw------- 1 root root 2756 8月 23 11:44 conf/tomcat-users.xml
-rw------- 1 root root 172576 8月 9 04:41 conf/web.xml
解释下:
server.xml #是主配置文件 定义虚拟主机
tomcat-users.xml #是状态监控和gui界面管理的身份认证配置文件
web.xml #是为webapp提供默认属性配置的文件 在tomcat启动时会先加载webapp属性的自定义配置文件/WEB-INF/web.xml,然后再加载此文件提供默认属性,一般此文件都不用任何修改,要定义属性时修改/WEB-INF/web.xml即可。对于此处的web.xml,唯一需要知道的是其内设置了主页文件名。
[root@zw_mysql tomcat]# grep -C 1 index conf/web.xml
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
四. 简单使用
4.1 添加虚拟主机
#01 创建站点目录
mkdir -pv /web/webapp
#02 书写检查代码页面
cat <<EOT >/web/webapp/index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> //注释
<html>
<head>
<title>JSP test page</title> //测试页标题
</head>
<body>
<% out.println("Welcome to test site,爱情 理想 远方");%> //测试页主体内容
</body>
</html>
EOT
#03 修改配置文件 添加虚拟主机
vim /opt/tomcat/conf/server.xml
// 添加 Context 内容
161 <Host name="localhost" appBase="webapps"
162 unpackWARs="true" autoDeploy="true">
163 <Context docBase="/web/webapp" path="" reloadable="false">
164 </Context>
解释下:
Host name: 定义域名或者IP
docBase:web应用的文档基准目录
reloadable: 设置监视“类”是否变化
path="": 设置默认“类
4.2 虚拟主机提供web服务
1)项目要求
域名 | 绝对路径+相对路径 | 返回内容 |
---|---|---|
www.zhangyz.com | /www/zhangyz | hello world from zhangyz Root |
www.zhangyz.com/ai/ | /www/zhangyz/ai/ | hello world from zhangyz ai Root |
www.zhangbb.com | /opt/tomcat/webapps/bb | hello world from zhangbb Root |
www.zhangbb.com/ni/ | /opt/tomcat/webapps/bb/ni | hello world from zhangbb ni Root |
#01 该示例通过设置虚拟主机来提供web服务,因为是入门示例,所以设置极其简单,
1) 需要修改$CATALINA_HOME/conf/server.xml文件为如下内容即可
2) tomcat安装在/opt/tomcat下因此 $CATALINA_HOME=/opt/tomcat。
3) 在engine容器中添加了两个Host容器
www.zhangyz.com /www/zhangyz ---> /www/zhangyz/ai
www.zhangbb.com /opt/tomcat/webapps/bb ---> /opt/tomcat/webapps/bb/ni
2)修改server.xml 配置
#01 备份原来的
mv server.xml server.xml-bak
vim server.xml
<!-- 从此处开始添加以下两个Host容器作为虚拟主机 绝对路径 -->
<!-- 定义一个在$CATALINA_HOME之外的虚拟主机 -->
<Host name="www.zhangyz.com" appBase="/www/zhangyz"
unpackWARs="true" autoDeploy="true">
<Context path="" docBase="/www/zhangyz" reloadable="true" />
<Context path="/ai" docBase="ai" reloadable="true" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="zhangyz_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<!-- 定义一个在$CATALINA_HOME/webapps下的虚拟主机 -->
<Host name="www.zhangbb.com" appBase="webapps/bb"
unpackWARs="true" autoDeploy="true">
<Context path="" docBase="" reloadable="true" />
<Context path="/ni" docBase="ni" reloadable="true" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="bb_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
除了engine中定义的默认localhost虚拟主机,另外布置了
两个虚拟主机: www.zhangyz.com 程序 站点目录路径:/www/zhangyz
www.zhangbb.com 程序 站点目录路径:/$CATALINA_HOME/webapps/bb
定义日志为相对路径:$CATALINA_HOME = /opt/tomcat 程序目录
3)创建站点目录和测试文件
#01 创建目录
mkdir -p /www/zhangyz/ai
mkdir -p /opt/tomcat/webapps/bb/ni
#02 检查
/www/zhangyz #虚拟主机 站点目录
/www/zhangyz/ai #虚拟主机 站点目录下方 uri
/opt/tomcat/webapps/bb #虚拟主机 站点目录
/opt/tomcat/webapps/bb/ni #虚拟主机 站点目录下方 uri
#03 书写测试文件 index.jsp
cat <<EOT >/www/zhangyz/index.jsp
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<html>
<body>
<% out.println("hello world from zhangyz Root"); %>
</body>
</html>
EOT
cat <<EOT >/www/zhangyz/ai/index.jsp
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<html>
<body>
<% out.println("hello world from zhangyz ai path "); %>
</body>
</html>
EOT
cat <<EOT >/opt/tomcat/webapps/bb/index.jsp
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<html>
<body>
<% out.println("hello world from zhangbb Root"); %>
</body>
</html>
EOT
cat <<EOT >/opt/tomcat/webapps/bb/ni/index.jsp
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<html>
<body>
<% out.println("hello world from zhangbb ni path"); %>
</body>
</html>
EOT
4)添加host解析
#01 添加
echo '10.0.0.102 www.zhangyz.com www.zhangbb.com ' >> /etc/hosts
5)重启服务访问测试
#01 重启服务
systemctl restart tomcat
#02 访问测试
[root@zw_mysql conf]# curl www.zhangyz.com:8080
<html>
<body>
hello world from zhangyz Root
</body>
</html>
[root@zw_mysql conf]# curl www.zhangyz.com:8080/ai/
<html>
<body>
hello world from zhangyz ai Root
</body>
</html>
[root@zw_mysql conf]# curl www.zhangbb.com:8080
<html>
<body>
hello world from zhangbb Root
</body>
</html>
[root@zw_mysql conf]# curl www.zhangbb.com:8080/ni/
<html>
<body>
hello world from zhangbb ni Root
</body>
</html>
4.2 tomcat 数据包处理流程
1)各个模块之间有嵌套的父子关系

- 各个模块之间有嵌套的父子关系
<server>
<service>
<connector PORT />
<engine>
<host name=www.zhangyz.com appBase=/www/zhangyz >
<context path="" docBase=/www/zhangyz />
<context path="/ai" docBase=/www/zhangyz/ai />
</host>
<host>
<context />
</host>
</engine>
</service>
</server>
- 解释下
-
server
组件是管理tomcat实例的组件,可以监听一个端口,从此端口上可以远程向该实例发送shutdown关闭命令。 -
service
组件是一个逻辑组件,用于绑定connector和container,有了service表示可以向外提供服务,就像是一般的daemon类服务的service。可以认为一个service就启动一个JVM,更严格地说,一个engine组件才对应一个JVM(定义负载均衡时,jvmRoute就定义在Engine组件上用来标识这个JVM),只不过connector也工作在JVM中。 -
connector
组件是
监听
组件,它有四个作用:
- (1).开启监听套接字,监听外界请求,并和客户端建立TCP连接;
- (2).使用protocolHandler解析请求中的协议和端口等信息,如http协议、AJP协议;
- (3).根据解析到的信息,使用processer将分析后的请求转发给绑定的Engine;
- (4).接收响应数据并返回给客户端。
-
container
是容器,它是一类组件,在配置文件(如server.xml)中没有体现出来。它包含4个容器类组件:engine容器、host容器、context容器和wrapper容器。 -
engine
容器用于从connector组件处接收已建立的TCP连接,还用于接收客户端发送的http请求并分析请求,然后按照分析的结果将相关参数传递给匹配出的虚拟主机。engine还用于指定默认的虚拟主机。 -
host
容器定义虚拟主机,由于tomcat主要是作为servlet容器的,所以为每个webapp指定了它们的根目录appBase。 -
context
容器主要是根据path和docBase获取一些信息,将结果交给其内的wrapper组件进行处理(它提供wrapper运行的环境,所以它叫上下文context)。一般来说,都采用默认的标准wrapper类,因此在context容器中几乎不会出现wrapper组件。 -
wrapper
容器对应servlet的处理过程。它开启servlet的生命周期,根据context给出的信息以及解析web.xml中的映射关系,负责装载相关的类,初始化servlet对象init()、执行servlet代码service()以及服务结束时servlet对象的销毁destory()。 -
executor
组件为每个Service组件提供线程池,使得各个connector和Engine可以从线程池中获取线程处理请求,从而实现tomcat的并发处理能力。一定要注意,Executor的线程池大小是为Engine组件设置,而不是为Connector设置的,Connector的线程数量由Connector组件的acceptorThreadCount属性来设置。如果要在配置文件中设置该组件,则必须设置在Connector组件的前面,以便在Connector组件中使用
executor
属性来引用配置好的Executor组件。如果不显式设置,则采用Connector组件上的默认配置,默认配置如下:- (1).maxThreads:最大线程数,默认值200。
- (2).minSpareThreads:最小空闲线程数,默认值25。
- (3).maxIdleTime:空闲线程的线程空闲多长时间才会销毁,默认值60000即1分钟。
- (4).prestartminSpareThreads:是否启动executor时就直接创建等于最小空闲线程数的线程,默认值为false,即只在有连接请求进入时才会创建。
根据上面描述的tomcat组件体系结构,处理请求的大致过程其实很容易推导出来:
Client(request)-->Connector-->Engine-->Host-->Context-->Wrapper(response data)-->Connector(response header)-->Client
2)和nginx conf 对应关系
撇开tomcat作为servlet容器的行为。它和apache、nginx的功能大致都能对应上。例如以nginx为例,以下是nginx提供web服务时的配置结构:
server {
listen PORT;
server_name www.zhangyz.com; # 对应于<host name=www.a.com>
location / { # 对应于context path=""
root html; # 对应于docBase
}
location /ai { # 对应于context path="/xuexi"
root html/xuexi;
}
}
#01 对应关系解释
connetcor组件类似于nginx的listen指令。
host容器类似于nginx的server指令
host容器中的name属性相当于nginx的server_name指令
engine组件则没有对应配置项,不过在nginx同样有engine的功能,例如默认的虚拟主机,分析URL来判断请求交给哪个虚拟主机处理等。
context容器相当于location指令
context容器的path属性相当于location的uri匹配路径
docBase相当于location的中的root指令,即DocumentRoot。
tomcat作为简单的web服务程序大致如此,但它的核心毕竟是处理servlet和jsp,它必须得管理好每个webapp。因此,对于tomcat来说,必须要掌握部署webapp的方式。
在tomcat上部署webapp时,必须要理解context的概念。对于tomcat而言,每个context都应该算是一个webapp,其路径由docBase决定,该目录存放的是归档的war文件或未归档的webapp相关文件,而host容器中的appBase(站点目录)则是虚拟主机整理webapp的地方,一个appBase下可以有多个webapp,即多个context。
五. appBase和docBase详细说明
这两货虽然意义很明确,但"潜规则"很严重。以下面的配置为例。
<host name=www.a.com appBase=/www/a >
<context path="" docBase=/www/a />
<context path="/xuexi" docBase=/www/a/xuexi />
</host>
- 定义
appBase是虚拟主机存放webapp的目录,它可以是相对路径,也可以是绝对路径。如果是相对路径,则相对于$CATALINA_HOME,严格并准确地说是$CATALINA_BASE。
path是URI的匹配路径,相当于nginx的location后的路径。tomcat要求每个虚拟主机必须配置一个空字符串的path,该条context作为URI无法被明确匹配时的默认context,它相当于nginx中location / {}的作用。
docBase则是每个webapp的存放目录(或者是已归档的war文件),它可以是相对路径,也可以是绝对路径,提供相对路径时它相对于appBase。该目录一般在appBase的目录下,但并不规定一定要放在appBase下。对于web服务来说,它相当于nginx的root指令,但对于webapp来说,一个context就相当于一个webapp,而docBase正是webapp的路径。
- 潜规则"在于默认的context如何提供。有以下几种情况:
- 明确定义了
<context path="" docBase=webappPATH>
,此时默认context的处理路径为webappPATH。 - 明确定义了
<context path="">
,但却没给定docBase属性,此时该默认context处理路径为appBase/ROOT目录,注意ROOT为大写。 - 完全没有定义
path=""
的context时,即host容器中没有明确的path="",此时将隐式定义一个默认context,处理路径为appBase/ROOT目录。 - 定义了path但没有定义docBase属性时,docBase将根据path推断出它的路径。推断的规则如下:(注:此时推断的不是默认context,而是对应context的docbase)
context path context name 推断出的docBase路径
--------------------------------------------------
/foo /foo foo
/foo/bar /foo/bar foo/bar
Empty String Empty String ROOT
显然,没有给定path=""或缺少docbase时,都以ROOT作为目录
六 webapp 目录体系
- 定义
webapp有特定的组织格式,是一种层次型目录结构,通常包含了servlet代码文件、jsp页面文件、类文件、部署描述符文件等等。
这些文件可能是以目录的形式存放,也可能会打包成各种归档格式的文件,如jar、war等。但jsp有规定,在web应用程序的根目录下,一般要有下面几个目录:
/WEB-INF: #此webapp的私有资源目录,从浏览器上是无法访问此目录资源的,通常web.xml放置于此目录
/WEB-INF/classes: #此webapp自有的类
/WEB-INF/lib: #此webapp自有能够打包为jar格式的类
/META-INF: #并非标准的webapp目录,有的应用程序才有。当该应用程序想独立定义自己的context.xml时可放入此目录,也是私有目录。
每个webapp要想被tomcat加载,一种方法是程序目录放在$catalina.home/webapps下,另一种方式是配置该webapp相关的context配置,使tomcat能找到此webapp。正如前文所说,webapp目录一般都会放在$catalina.home/webapps下。
- 简单部署示例:
#01 下载官方提供的 war 包
cd /opt/tomcat/webapps
https://tomcat.apache.org/tomcat-8.5-doc/appdev/sample/sample.war --no-check-certificate
#02 重启服务
systemctl restart tomcat
[root@zw_mysql tomcat]# ll webapps/
总用量 12
drwxr-xr-x 3 root root 33 8月 23 14:22 bb
drwxr-x--- 16 root root 4096 8月 23 11:04 docs
drwxr-x--- 7 root root 99 8月 23 11:04 examples
drwxr-x--- 6 root root 79 8月 23 11:04 host-manager
drwxr-x--- 6 root root 114 8月 23 11:04 manager
drwxr-x--- 3 root root 223 8月 23 11:04 ROOT
drwxr-x--- 5 root root 86 8月 23 15:03 sample
-rw-r--r-- 1 root root 4606 3月 26 2016 sample.war
发现多了一个 sample
解释下: 于war类归档程序:将归档文件复制到$CATALINA_BASE/webapps/目录中,并重启tomcat即可,tomcat会自动展开war归档
- 访问测试
http://192.168.5.16:8080/sample/

七. server.xml详解
tomcat配置文件中配置的是各个组件的属性,全局配置文件为$CATALINA_HOME/conf/server.xml,主要的组件有以下几项:Server,Service,Connector,Engine,Host,Alias,Context,Valve等。配置完配置文件后需要重启tomcat,但在启动后一定要检查tomcat是否启动成功,因为即使出错,很多时候它都不会报错,可从监听端口判断。
配置方法见官方手册,在页面的左边有各个组件的链接。
tomcat的配置文件都是xml文件,以下是xml文件的常见规则:
- 文件第一行设置xml标识,表示该文件是xml格式的文件。例如
<?xml version="1.0" encoding="UTF-8"?>
。 - xml文件的注释方法为
<!-- XXX -->
,这可以是单行注释,也可以多行注释,只要前后注释符号能对应上,中间的内容都是注释。 - 定义属性时有两种方式:单行定义和多行定义。例如:
<!-- 单行定义的方式 -->
<NAME key=value />
<!-- 多行定义的方式 -->
<NAME key=value>
</NAME>
下面个组件的配置中有些地方使用了相对于$CATALINA_BASE的相对路径,它和$CATALINA_HOME小有区别。如果只有一个tomcat实例,则它们是等价的,都是tomcat的安装路径。如果有多个tomcat实例,则$CATALINA_HOME表示的是安装路径,而$CATALINA_BASE表示的是各实例所在根目录。关于tomcat多实例,见running.txt中对应的说明。
7.1 顶级元素server
server组件定义的是一个tomcat实例。默认定义如下:
<Server port="8005" shutdown="SHUTDOWN">
</Server>
它默认监听在8005端口以接收shutdown命令。要启用多个tomcat实例,将它们监听在不同的端口即可。这个端口的定义为管理员提供一个关闭实例的便捷途径,可以直接telnet至此端口使用SHUTDOWN命令关闭此实例。不过基于安全角度的考虑,通常不允许远程进行。
Server的相关属性:
className
:用于实现此组件的java类的名称,这个类必须实现接口org.apache.catalina.Server。不给定该属性时将采用默认的标准类org.apache.catalina.core.StandardServer;address
:监听端口绑定的地址。如不指定,则默认为Localhost,即只能在localhost上发送SHUTDOWN命令;port
:接收shutdown指令的端口,默认仅允许通过本机访问,默认为8005;shutdown
:通过TCP/IP连接发往此Server用于实现关闭tomcat实例的命令字符串。
在server组件中可嵌套一个或多个service组件。
7.2 顶级元素service
定义了service就能提供服务了。service组件中封装connector和container,它同时也表示将此service中的connector和container绑定起来,即由它们组成一个service向外提供服务。默认定义如下:
<Service name="Catalina">
</Service>
Service相关的属性:
className
:用于实现service的类名,这个类必须实现org.apache.catalina.Service接口。不给定该属性时将采用默认的标准类org.apache.catalina.core.StandardService。name
:此service的显示名称,该名称主要用于在日志中进行标识service。一般来说无关紧要,默认为Catalina。
7.3 执行器executor
执行器定义tomcat各组件之间共享的线程池。在以前,每个connector都会独自创建自己的线程池,但现在,可以定义一个线程池,各组件都可以共享该线程池,不过主要是为各connector之间提供共享。注意,executor创建的是共享线程池,如果某个connector不引用executor创建的线程池,那么该connector仍会根据自己指定的属性创建它们自己的线程池。
连接器必须要实现org.apache.catalina.Executor接口。它是一个嵌套在service组件中的元素,为了挑选所使用的connector,该元素还必须定义在connector元素之前。
默认的定义如下:
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
其中该组件的属性有:
className
:用于实现此组件的java类的名称,这个类必须实现接口org.apache.catalina.Executor。不给定该属性时将采用默认的标准类org.apache.catalina.core.StandardThreadExecutor;name
:该线程池的名称,其他组件需要使用该名称引用该线程池。
标准类的属性包括:
threadPriority
:线程优先级,默认值为5。daemon
:线程是否以daemon的方式运行,默认值为true。namePrefix
:执行器创建每个线程时的名称前缀,最终线程的名称为:namePrefix+threadNumber。maxThreads
:线程池激活的最大线程数量。默认值为200。minSpareThreads
:线程池中最少空闲的线程数量。默认值为25。maxIdleTime
:在空闲线程关闭前的毫秒数。除非激活的线程数量小于或等于minSpareThreads的值,否则会有空闲线程的出现。默认值为60000,即空闲线程需要保留1分钟的空闲时间才被杀掉。maxQueueSize
:可执行任务的最大队列数,达到队列上限时的连接请求将被拒绝。prestartminSpareThreads
:在启动executor时是否立即创建minSpareThreads个线程数,默认为false,即在需要时才创建线程。
例如在connector中指定所使用的线程池,方式如下:
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
5.4 连接器connector
连接器用于接收客户端发送的请求并返回响应给客户端。一个service中可以有多个connector。有多种connector,常见的为http/1.1,http/2和ajp(apache jserv protocol)。在tomcat中,ajp连接协议类型专用于tomcat前端是apache反向代理的情况下。
因此tomcat可以扮演两种角色:
- Tomcat仅作为应用程序服务器:请求来自于前端的web服务器,这可能是Apache, IIS, Nginx等;
- Tomcat既作为web服务器,也作为应用程序服务器:请求来自于浏览器。
Tomcat应该考虑工作情形并为相应情形下的请求分别定义好需要的连接器才能正确接收来自于客户端的请求。
此处暂先介绍HTTP/1.1连接器的属性设置。ajp后文再做介绍。
HTTP连接器表示支持HTTP/1.1协议的组件。设置了该连接器就表示catalina启用它的独立web服务功能,当然,肯定也提供它必须的servlets和jsp执行功能。在一个service中可以配置一个或多个连接器,每个连接器都可以将请求转发给它们相关联的engine以处理请求、创建响应。
每个流入的请求都需要一个独立的线程来接收。当并发请求数量超出maxThreads指定的值时,多出的请求将被堆叠在套接字中,直到超出acceptCount指定的值。超出accpetCount的请求将以"connection refused"错误进行拒绝。
默认的定义如下:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
HTTP连接器的属性实在太多,详细配置方法见官方手册。通常定义HTTP连接器时必须定义的属性只有"port"。
address
:指定连接器监听的地址,默认为所有地址,即0.0.0.0。maxThreads
:支持的最大并发连接数,默认为200;如果引用了executor创建的共享线程池,则该属性被忽略。acceptCount
:设置等待队列的最大长度;通常在tomcat所有处理线程均处于繁忙状态时,新发来的请求将被放置于等待队列中;maxConnections
:允许建立的最大连接数。acceptCount和maxThreads是接受连接的最大线程数。存在一种情况,maxConnections小于acceptCount时,超出maxConnections的连接请求将被接收,但不会与之建立连接。port
:监听的端口,默认为0,此时表示随机选一个端口,通常都应该显式指定监听端口。protocol
:连接器使用的协议,用于处理对应的请求。默认为HTTP/1.1,此时它会自动在基于Java NIO或APR/native连接器之间进行切换。定义AJP协议时通常为AJP/1.3。redirectPort
:如果某连接器支持的协议是HTTP,当接收客户端发来的HTTPS请求时,则转发至此属性定义的端口。connectionTimeout
:等待客户端发送请求的超时时间,单位为毫秒,默认为60000,即1分钟;注意,这时候连接已经建立。keepAliveTimeout
:长连接状态的超时时间。超出该值时,长连接将关闭。enableLookups
:是否通过request.getRemoteHost()进行DNS查询以获取客户端的主机名;默认为true,应设置为false防止反解客户端主机;compression
:是否压缩数据。默认为off。设置为on时表示只压缩text文本,设置为force时表示压缩所有内容。应该在压缩和sendfile之间做个权衡。useSendfile
:该属性为NIO的属性,表示是否启用sendfile的功能。默认为true,启用该属性将会禁止compression属性。
当协议指定为HTTP/1.1时,默认会自动在NIO/APR协议处理方式上进行按需切换。如要显式指定协议,方式如下:
<connector port="8080" protocol="HTTP/1.1">
<connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol">
<connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol">
<connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol">
其中NIO是C/C++的非阻塞IO复用模型在JAVA中的IO实现,NIO2即AIO是异步NIO,即异步非阻塞IO:
NioProtocol :non blocking Java NIO connector
Nio2Protocol:non blocking Java NIO2 connector
AprProtocol :the APR/native connector
它们之间的异同点如下表所示:
Java Nio Connector | Java Nio2 Connector | APR/native Connector | |
---|---|---|---|
Classname | Http11NioProtocol | Http11Nio2Protocol | Http11AprProtocol |
Tomcat Version | 6.x onwards | 8.x onwards | 5.5.x onwards |
Support Polling | YES | YES | YES |
Polling Size | maxConnections | maxConnections | maxConnections |
Read Request Headers | Non Blocking | Non Blocking | Non Blocking |
Read Request Body | Blocking | Blocking | Blocking |
Write Response Headers and Body | Blocking | Blocking | Blocking |
Wait for next Request | Non Blocking | Non Blocking | Non Blocking |
SSL Support | Java SSL or OpenSSL | Java SSL or OpenSSL | OpenSSL |
SSL Handshake | Non blocking | Non blocking | Blocking |
Max Connections | maxConnections | maxConnections | maxConnections |
下面是一个定义了多个属性的SSL连接器:
<Connector port="8443"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" acceptCount="100" debug="0" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
5.5 容器类engine
engine是service组件中用来分析协议的引擎机器,它从一个或多个connector上接收请求,并将请求交给对应的虚拟主机进行处理,最后返回完整的响应数据给connector,通过connector将响应数据返回给客户端。
只有一个engine元素必须嵌套在每个service中,且engine必须在其所需要关联的connector之后,这样在engine前面的connector都可以被此engine关联,而在engine后面的connector则被忽略,因为一个service中只允许有一个engine。
定义方式大致如下:
<Engine name="Catalina" defaultHost="localhost">
</Engine>
<Engine name="Standalone" defaultHost="localhost" jvmRoute="TomcatA">
</Engine>
常用的engine属性有:
className
:实现engine的类,该类必须实现org.apache.catalina.Engine接口。不给定该属性时将采用默认的标准类org.apache.catalina.core.StandardEngine。defaultHost
:指定处理请求的默认虚拟主机。在Engine中定义的多个虚拟主机的主机名称中至少有一个跟defaultHost定义的主机名称同名。name
:Engine组件的名称,用于记录日志和错误信息,无关紧要的属性,可随意给定。jvmRoute
:在启用session粘性时指定使用哪种负载均衡的标识符。所有的tomcat server实例中该标识符必须唯一,它会追加在session标识符的尾部,因此能让前端代理总是将特定的session转发至同一个tomcat实例上。- 注意,jvmRoute同样可以使用jvmRoute的系统属性来设置。如果此处设置了jvmRoute,则覆盖jvmRoute系统属性。关于jvmRoute的使用,在后面tomcat ajp负载均衡的文章中介绍。
engine是容器中的顶级子容器,其内可以嵌套一个或多个Host作为虚拟主机,且至少一个host要和engine中的默认虚拟主机名称对应。除了host,还可以嵌套releam和valve组件。
5.6 容器类host
host容器用来定义虚拟主机。engine从connector接收到请求进行分析后,会将相关的属性参数传递给对应的(筛选方式是从请求首部的host字段和虚拟主机名称进行匹配)虚拟host进行处理。如果没有合适的虚拟主机,则传递给默认虚拟主机。因此每个容器中必须至少定义一个虚拟主机,且必须有一个虚拟主机和engine容器中定义的默认虚拟主机名称相同。
大致定义方式如下:
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
</Host>
常用属性说明:
className
:实现host容器的类,该类必须实现org.apache.catalina.Host接口。不给定该属性时将采用默认的标准类org.apache.catalina.core.StandardHost。name
:虚拟主机的主机名,忽略大小写(初始化时会自动转换为小写)。可以使用前缀星号通配符,如"*.a.com"。使用了星号前缀的虚拟主机的匹配优先级低于精确名称的虚拟主机。appBase
:此Host的webapps目录,即webapp部署在此虚拟主机上时的存放目录。包括非归档的web应用程序目录和归档后的WAR文件的目录。使用相对路径时基于$CATALINA_BASE。xmlBase
:部署在此虚拟主机上的context xml目录。startStopThreads
:启动context容器时的并行线程数。如果使用了自动部署功能,则再次部署或更新时使用相同的线程池。autoDeploy
:在Tomcat处于运行状态时放置于appBase目录中的应用程序文件是否自动进行deploy或自动更新部署状态。这等于同时开启了deployOnStartup属性和reload/redeploy webapp的功能。触发自动更新时将默认重载该webapp。默认为true。unpackWars
:在执行此webapps时是否先对归档格式的WAR文件解压再运行,设置为false时则直接执行WAR文件;默认为true。设置为false时会损耗性能。workDir
:该虚拟主机的工作目录。每个webapp都有自己的临时IO目录,默认该工作目录为$CATALINA_BASE/work。
大多数时候都只需设置虚拟主机名称name和appBase属性即可,其余采用默认,默认时会自动部署webapp。有时候还需要管理多个站点名称,即主机别名。可以使用Alias为Host指定的主机名定义主机别名。如:
<Host name="web.a.com" appBase="webapps" unpackWARs="true">
<Alias>www.a.com</Alias>
</Host>
自动部署指的是自动装载webapp以提供相关webapp的服务。
5.7 容器类context
connector和container是整个tomcat的心脏,而context则是container的心脏,更是tomcat心脏的心脏。它是真正管理servlet的地方,它的配置影响了servlet的工作方式。
一个context代表一个webapp。servlet中规定,每个webapp都必须基于已归档的WAR(WEB application archive)文件或基于非归档相关内容所在目录。
catalina基于对请求URI与context中定义的path进行最大匹配前缀的规则进行挑选,从中选出使用哪个context来处理该HTTP请求。这相当于nginx的location容器,catalina的path就相当于location的path,它们的作用是相同的。
每个context都必须在虚拟主机容器host中有一个唯一的context name。context的path不需要唯一,因为允许同一个webapp不同版本的共存部署。此外,必须要有一个context的path为0长度的字符串(如<Context path="" docBase="ROOT"/>
),该context是该虚拟主机的默认webapp,用于处理所有无法被虚拟主机中所有context path匹配的请求(当然,不定义也可以,此时将自动隐式提供,见前文所述)。
关于context name,它是从context path推断出来的,不仅如此,其余几个属性如context basefile name也是由此推断出来的。规则如下:
- 如果path不为空,则context name等于context path,basefile name取path中去除前缀"/"后的路径,且所有"/"替换为"#"。
- 如果path为空,则context name也为空,而basefile为ROOT(注意是大写)。
例如:
context path context name basefile name deploy examples
-----------------------------------------------------------------
/foo /foo foo foo.xml,foo.war,foo
/foo/bar /foo/bar foo#bar foo#bar.xml,foo#bar.war,foo#bar
Empty String Empty String ROOT ROOT.xml,ROOT.war,ROOT
配置context时,强烈建议不要定义在server.xml中,因为定义在conf/server.xml中时,只能通过重启tomcat来重载生效,也就是说无法自动部署应用程序了。**虽说官方如此推荐,但大多数人出于习惯和方便,还是会直接写在server.xml中,这并没有什么问题,无非是重启一下而已。**
可以考虑定义在/META-INF/context.xml中,如果此时设置了copyXML属性,在部署时会将此context.xml复制到$CATALINA_BASE/conf/enginename/hostname/下,并重命名为"basefile name.xml"。也可以直接定义在$CATALINA_BASE/conf/enginename/hostname/下的.xml文件中,该路径的xml优先级高于/META-INF/context.xml。
还可以定义默认的context.xml文件,包括两种:(1)定义在$CATALINA_BASE/conf/context.xml中,该默认context对所有webapp都生效;(2)定义在$CATALINA_BASE/conf/[enginename]/[hostname]/context.xml.default中,该默认context只对该虚拟主机中的所有webapp生效。
定义方式大致如下:
<Host name="www.a.com" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context path="" docBase="ROOT"/>
<Context path="/bbs" docBase="web/bbs" reloadable="true"/>
</Host>
其中第一个context的path为空字符串,表示它是默认的context。当浏览器中输入www.a.com时,由于无法匹配第二个context,所以被默认即第一个context处理,当浏览器中输入www.a.com/bbs时,将被第二个context处理,它将执行web/bbs所对应的webapp,并返回相关内容。
在context容器中可以定义非常多的属性,详细内容见官方手册,以下是常见的几个属性:
className
:实现host容器的类,该类必须实现org.apache.catalina.Context接口。不给定该属性时将采用默认的标准类org.apache.catalina.core.StandardContext。cookies
:默认为true,表示启用cookie来标识session。docBase
:即DocumentRoot,是该webapp的context root,即归档WAR文件所在目录或非归档内容所在目录。可以是绝对路径,也可以是相对于该webapp appBase的相对路径。path
:定义webapp path。注意,当path=""时,表示默认的context;另外只有在server.xml中才需要定义该属性,其他所有情况下都不能定义该属性,因为会根据docBase和context的xml文件名推断出path。reloadable
:是否监控/WEB-INF/class和/WEB-INF/lib两个目录中文件的变化,变化时将自动重载。在测试环境下该属性很好,但在真实生产环境部署应用时不应该设置该属性,因为监控会大幅增加负载,因此该属性的默认值为false。wrapperClass
:实现wrapper容器的类,wrapper用于管理该context中的servlet,该类必须实现org.apache.catalina.Wrapper接口,如果不指定该属性则采用默认的标准类。xmlNamespaceAware
:和web.xml的解析方式有关。默认为true,设置为false可以提升性能。xmlValidation
:和web.xml的解析方式有关。默认为true,设置为false可以提升性能。
5.8 被嵌套类realm
realm定义的是一个安全上下文,就像是以哪种方式存储认证时的用户和组相关的数据库。有多种方式可以实现数据存放:
- JAASRealm:基于Java Authintication and Authorization Service实现用户认证;
- JDBCRealm:通过JDBC访问某关系型数据库表实现用户认证;
- JNDIRealm:基于JNDI使用目录服务实现认证信息的获取;
- MemoryRealm:查找tomcat-user.xml文件实现用户信息的获取;
- UserDatabaseRealm:基于UserDatabase文件(通常是tomcat-user.xml)实现用户认证,它实现是一个完全可更新和持久有效的MemoryRealm,因此能够跟标准的MemoryRealm兼容;它通过JNDI实现;
下面是一个常见的使用UserDatabase的配置:
1
2
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
下面是一个使用JDBC方式获取用户认证信息的配置:
<Realm className="org.apache.catalina.realm.JDBCRealm" debug="99"
driverName="org.gjt.mm.mysql.Driver"
connectionURL="jdbc:mysql://localhost/authority"
connectionName="test" connectionPassword="test"
userTable="users" userNameCol="user_name"
userCredCol="user_pass"
userRoleTable="user_roles" roleNameCol="role_name" />
5.9 被嵌套类valve
Valve中文意思是阀门,类似于过滤器,它可以工作于Engine和Host/Context之间、Host和Context之间以及Context和Web应用程序的某资源之间。一个容器内可以建立多个Valve,而且Valve定义的次序也决定了它们生效的次序。
有多种不同的Valve:
- AccessLogValve:访问日志Valve;
- ExtendedAccessValve:扩展功能的访问日志Valve;
- JDBCAccessLogValve:通过JDBC将访问日志信息发送到数据库中;
- RequestDumperValve:请求转储Valve;
- RemoteAddrValve:基于远程地址的访问控制;
- RemoteHostValve:基于远程主机名称的访问控制;
- SemaphoreValve:用于控制Tomcat主机上任何容器上的并发访问数量;
- JvmRouteBinderValve:在配置多个Tomcat为以Apache通过mod_proxy或mod_jk作为前端的集群架构中,当期望停止某节点时,可以通过此Valve将用记请求定向至备用节点;使用此Valve,必须使用JvmRouteSessionIDBinderListener;
- ReplicationValve:专用于Tomcat集群架构中,可以在某个请求的session信息发生更改时触发session数据在各节点间进行复制;
- SingleSignOn:将两个或多个需要对用户进行认证webapp在认证用户时连接在一起,即一次认证即可访问所有连接在一起的webapp;
- ClusterSingleSingOn:对SingleSignOn的扩展,专用于Tomcat集群当中,需要结合ClusterSingleSignOnListener进行工作;
其中RemoteHostValve和RemoteAddrValve可以分别用来实现基于主机名称和基于IP地址的访问控制,控制本身可以通过allow或deny来进行定义,这有点类似于Apache的访问控制功能。如下面的Valve实现了仅允许本机访问/probe:
<Context privileged="true" path="/probe" docBase="probe">
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.0\.0\.1"/>
</Context>
其中相关属性定义有:
- className:在对应位置的后缀上加上".valves.RemoteHostValve"或".valves.RemoteAddrValve";
- allow:以逗号分开的允许访问的IP地址列表,支持正则,点号“.”用于IP地址时需要转义;仅定义allow项时,非明确allow的地址均被deny;
- deny: 以逗号分开的禁止访问的IP地址列表,支持正则;使用方式同allow;仅定义deny项时,非明确deny的地址均被allow;
另外一个常用的Valve为AccessLogValve,定义方式大致如下:
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
其中prefix和suffix表示日志文件的前缀名称和后缀名称。pattern表示记录日志时的信息和格式。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)