共计 21106 个字符,预计需要花费 53 分钟才能阅读完成。
1. 入门示例:虚拟主机提供 web 服务
该示例通过设置虚拟主机来提供 web 服务,因为是入门示例,所以设置极其简单,只需修改 $CATALINA_HOME/conf/server.xml 文件为如下内容即可。其中大部分都采用了默认设置,只是在 engine 容器中添加了两个 Host 容器。
<?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" enableLookups="false" />
<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 容器作为虚拟主机 -->
<Host name="www.longshuai.com" appBase="/www/longshuai"
unpackWARs="true" autoDeploy="true">
<Context path="" docBase="/www/longshuai" reloadable="true" />
<Context path="/xuexi" docBase="xuexi" reloadable="true" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="longshuai_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="www.xiaofang.com" appBase="/www/xiaofang"
unpackWARs="true" autoDeploy="true">
<Context path="" docBase="/www/xiaofang" reloadable="true" />
<Context path="/xuexi" docBase="xuexi" reloadable="true" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="xiaofang_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<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>
除了 engine 中定义的默认 localhost 虚拟主机,另外布置了两个虚拟主机 www.longshuai.com 和 www.xiaofang.com,它们的程序目录分别为 /www/longshuai 和 /www/xiaofang,所以需要提前建立好这两个目录。另外,在 context 中定义了 docBase,对于 uri 路径 /xuexi,它的文件系统路径为 /www/{longshuai,xiaofang}/xuexi 目录,所以也要在上面两个程序根目录中定义好 xuexi 目录。除此之外,还分别为这 3 个虚拟主机定义了日志,它们的路径为相对路径 logs,相对于 $CATALINA_HOME。
再提供 appBase 目录和 docBase 目录。
mkdir -p /www/{longshuai,xiaofang}/xuexi
再提供测试用的 index.jsp 文件。内容大致如下,分别复制到 /www/{longshuai,xiaofang}/ 和 /www/{longshuai,xiaofang}/xuexi/ 下,并将 out.println 的输出内容分别稍作修改,使能够区分读取的是哪个 index.jsp。
<%@ page language="Java" %>
<%@ page import="java.util.*" %>
<html>
<body>
<% out.println("hello world from longshuai Root"); %>
</body>
</html>
最后重启 catalina。
catalina.sh stop
catalina.sh start
再测试主机上添加 www.{longshuai,xiaofang}.com 的 host 记录。例如在 windows 上,在 C:\Windows\System32\drivers\etc\hosts 中添加如下记录:
192.168.100.22 www.longshuai.com www.xiaofang.com
在浏览器中进行测试,结果如下:
2. tomcat 体系结构基本说明
如下图:
tomcat 高度模块化,各个模块之间有嵌套的父子关系。如果使用配置文件来描述,可以大致简化为如下:
<server>
<service>
<connector PORT />
<engine>
<host name=www.a.com appBase=/www/a >
<context path="" docBase=/www/a />
<context path="/xuexi" docBase=/www/a/xuexi />
</host>
<host>
<context />
</host>
</engine>
</service>
</server>
其中:server组件是工作在后台管理 tomcat 实例的组件,可以监听一个端口,从此端口上可以远程向该实例发送 shutdown 关闭命令。
service组件是一个逻辑组件,绑定 connector 和 containor,有了 service 表示可以向外提供服务,就像是一般的 daemon 类服务的 service。
connector组件是服务监听组件,用于监听外界请求并建立 TCP 连接,然后将连接交给 containor,之后可以从此连接传输数据,例如接收 http 请求,发送 http 响应等。
containor是容器,在配置文件中没有体现出来,它包含 4 个容器类组件:engine 容器、host 容器、context 容器和 wrapper 容器。
engine容器用于从 connector 组件处接收已建立的 TCP 连接,还用于接收客户端发送的 http 请求并分析请求,然后按照分析的结果将相关参数传递给匹配出的虚拟主机。engine 还用于指定默认的虚拟主机。
host容器定义虚拟主机,由于 tomcat 主要是作为 servlet 容器的,所以为每个 web 应用程序指定了它们的根目录 appBase。
context容器对应 servlet 容器的处理过程。还可以指定相关的 wrapper 容器类,当然一般都采用默认的标准 wrapper 类。
Tomcat 配置(一):背景知识和安装 Tomcat http://www.linuxidc.com/Linux/2017-10/147942.htm
最后当请求处理完毕后,context 将响应数据返回给 host,再返回给 engine,再返回给 connector,最后返回给客户端。
撇开 tomcat 作为 servlet 容器的行为。它和 apache、nginx 的功能大致都能对应上。例如以 nginx 为例,以下是 nginx 提供 web 服务时的配置结构:
server {listen PORT;
server_name www.a.com; # 对应于 <host name=www.a.com>
location / {# 对应于 context path=""
root html; # 对应于 docBase
}
location /xuexi {# 对应于 context path="/xuexi"
root html/xuexi;
}
}
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。
3. tomcat 的 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 作为目录。以下是几个定义示例:
# 虚拟主机中没有定义任何 context,将以 appBase 下的 ROOT 作为默认处理路径
<Host appBase="webapps">
</Host>
# 没有定义 path="" 的 context,但定义了 path 非空的 context,也将以 ROOT 作为默认处理路径
# 如果下面的 Context 容器中省略 docBase 属性,则推断出该 context 的 docBase 路径为 appBase/xuexi
<Host appBase="webapps">
<Context path="/xuexi" docBase="webappPATH" />
</Host>
# 某个 context 定义了 path="",该 context 将作为默认 context
# 但该默认 context 如果没有定义 docBase,将推断出其 docBase 路径为 appBase/ROOT
<Host appBase="webapps">
<Context path="" docBase="webappPATH" />
</Host>
# 某个 context 定义了 path="",该 context 将作为默认 context
# 下面的默认 context 明确定义了 docBase
<Host appBase="webapps">
<Context path="" docBase="webappPATH" />
</Host>
4. webapp 体系结构
webapp 有特定的组织格式,是一种层次型目录结构,通常包含了 servlet 代码文件、jsp 页面文件、类文件、部署描述符文件等等。
这些文件可能是以目录的形式存放,也可能会打包成各种归档格式的文件,如 jar、war 等。但 jsp 有规定,在 web 应用程序的根目录下,一般要有下面几个目录:
- /WEB-INF:此 webapp 的私有资源目录,从浏览器上是无法访问此目录资源的,通常 web.xml 和 context.xml 均放置于此目录
- /WEB-INF/classes:此 webapp 自有的类
- /WEB-INF/lib:此 webapp 自有能够打包为 jar 格式的类
- /META-INF:并非标准的 webapp 目录,有的应用程序才有。当该应用程序想独立定义自己的 context.xml 时可放入此目录,也是私有目录。
每个 webapp 要想被 tomcat 加载,一种方法是程序目录放在 $catalina.home/webapps 下,另一种方式是配置该 webapp 相关的 context 配置,使 tomcat 能找到此 webapp。之所以可以直接放在 $catalina.home/webapps 下,是因为默认的 localhost 虚拟主机的 appBase=”webapps”,该目录下的所有内容它都可以自动查找,不过要注意,此时要想访问此 webapp 只能通过虚拟主机是 localhost。
简单部署示例:
(1)对于 war 类归档程序:将归档文件复制到 $CATALINA_BASE/webapps/ 目录中,并重启 tomcat 即可,tomcat 会自动展开 war 归档。例如官方提供了一个 sample.war 作为 tomcat 学习初级示例(https://tomcat.apache.org/tomcat-8.5-doc/appdev/sample/sample.war ),下载后只需将其放入 webapps 下即可。
(2)在程序的开发过程中,很多时候是未归档程序,这时可以手动创建目录来实现部署。需要创建的目录有 webapps/yourapp,此目录下还要创建 WEB-INF 目录,在 WEB-INF 目录中还要创建 classes 和 lib 目录。然后将 jsp 文件放在对应目录下即可,如写一个测试的 index.jsp 放在 yourapp 目录下。
5. tomcat 配置文件 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 中对应的说明。
5.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 组件。
5.2 顶级元素 service
定义了 service 就能提供服务了。service 组件中封装 connector 和 containor,它同时也表示将此 service 中的 connector 和 containor 绑定起来,即由它们组成一个 service 向外提供服务。默认定义如下:
<Service name="Catalina">
</Service>
Service 相关的属性:
className
:用于实现 service 的类名,这个类必须实现 org.apache.catalina.Service 接口。不给定该属性时将采用默认的标准类 org.apache.catalina.core.StandardService。name
:此 service 的显示名称,该名称主要用于在日志中进行标识 service。一般来说无关紧要,默认为 Catalina。
5.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 和 webBase 属性即可,其余采用默认,默认时会自动部署 webapp。有时候还需要管理多个站点名称,即主机别名。可以使用 Alias 为 Host 指定的主机名定义主机别名。如:
<Host name="web.a.com" appBase="webapps" unpackWARs="true">
<Alias>www.a.com</Alias>
</Host>
自动部署指的是自动装载 webapp 以提供相关 webapp 的服务。
5.7 容器类 context
connector 和 containor 是整个 tomcat 的心脏,而 context 则是 containor 的心脏,更是 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 的配置:
<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 表示记录日志时的信息和格式。
更多 Tomcat 相关教程见以下内容:
CentOS 6.6 下安装配置 Tomcat 环境 http://www.linuxidc.com/Linux/2015-08/122234.htm
RedHat Linux 5.5 安装 JDK+Tomcat 并部署 Java 项目 http://www.linuxidc.com/Linux/2015-02/113528.htm
Tomcat 权威指南(第二版)(中英高清 PDF 版 + 带书签) http://www.linuxidc.com/Linux/2015-02/113062.htm
Tomcat 安全配置与性能优化 http://www.linuxidc.com/Linux/2015-02/113060.htm
Linux 下使用 Xshell 查看 Tomcat 实时日志中文乱码解决方案 http://www.linuxidc.com/Linux/2015-01/112395.htm
CentOS 64-bit 下安装 JDK 和 Tomcat 并设置 Tomcat 开机启动操作步骤 http://www.linuxidc.com/Linux/2015-01/111485.htm
Ubuntu 16.04 下安装 Tomcat 8.5.9 http://www.linuxidc.com/Linux/2017-06/144809.htm
Ubuntu 16.04 安装 Tomcat 8 图解 http://www.linuxidc.com/Linux/2017-10/147773.htm
Tomcat 单机多实例部署 - 多项目部署 http://www.linuxidc.com/Linux/2017-10/147259.htm
Tomcat 的详细介绍:请点这里
Tomcat 的下载地址:请点这里
本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-12/149921.htm