1. 入门示例:虚拟主机提供web服务
该示例通过设置虚拟主机来提供web服务,因为是入门示例,所以设置极其简单,只需修改$CATALINA_HOME/conf/server.xml文件为如下内容即可。其中大部分都采用了默认设置,只是在engine容器中添加了两个Host容器。
<"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/webapps/longshuai" unpackWARs="true" autoDeploy="true"> <Context path="" docBase="/www/webapps/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/webapps/xiaofang" unpackWARs="true" autoDeploy="true"> <Context path="" docBase="/www/webapps/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类。
最后当请求处理完毕后,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如何提供。有以下几种情况:
1.明确定义了<context path="" docBase=webappPATH>,此时默认context的处理路径为webappPATH。
2.明确定义了<context path="">,但却没给定docBase属性,此时该默认context处理路径为appBase/ROOT目录,注意ROOT为大写。
3.完全没有定义path=""的context时,即host容器中没有明确的path="",此时将隐式定义一个默认context,处理路径为appBase/ROOT目录。
4.定义了path但没有定义docBase属性时,docBase将根据path推断出它的路径。推断的规则如下:
context path context name 推断出的docBase路径 -------------------------------------------------- /foo /foo foo /foo/bar /foo/bar foo/bar Empty String Empty String ROOT
以下是几个定义示例:
# 虚拟主机中没有定义任何context,将以appBase下的ROOT作为默认处理路径 <Host appBase="webapps"> </Host> # 没有定义path=""的context,但定义了path非空的context,也将以ROOT作为默认处理路径 # 如果下面的Context容器中省略docBase属性,则推断出其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. tomcat配置文件server.xml详解
tomcat配置文件中配置的是各个组件的属性,全局配置文件为$CATALINA_HOME/conf/server.xml,主要的组件有以下几项:Server,Service,Connector,Engine,Host,Alias,Context,Valve等。配置完配置文件后需要重启tomcat,但在启动后一定要检查tomcat是否启动成功,因为即使出错,很多时候它都不会报错,可从监听端口判断。
配置方法见官方手册,在页面的左边有各个组件的链接。
tomcat的配置文件都是xml文件,以下是xml文件的常见规则:
1.文件第一行设置xml标识,表示该文件是xml格式的文件。例如<"1.0" encoding="UTF-8"?>。
2.xml文件的注释方法为<!-- XXX -->,这可以是单行注释,也可以多行注释,只要前后注释符号能对应上,中间的内容都是注释。
3.定义属性时有两种方式:单行定义和多行定义。例如:
<!-- 单行定义的方式 --> <NAME key=value /> <!-- 多行定义的方式 --> <NAME key=value> </NAME>
下面个组件的配置中有些地方使用了相对于$CATALINA_BASE的相对路径,它和$CATALINA_HOME小有区别,如果只有一个tomcat实例,则它们是等价的,都是tomcat的安装路径。如果有多个tomcat实例,则$CATALINA_HOME表示的是安装路径,而$CATALINA_BASE表示的是各实例所在根目录。关于tomcat多实例,见running.txt中对应的说明。
4.1 顶级元素server
server组件定义的是一个tomcat实例。默认定义如下:
<Server port="8005" shutdown="SHUTDOWN"> </Server>
它默认监听在8005端口以接收shutdown命令。要启用多个tomcat实例,将它们监听在不同的端口即可。这个端口的定义为管理员提供一个关闭实例的便捷途径,可以直接telnet至此端口使用SHUTDOWN命令关闭此实例。不过基于安全角度的考虑,通常不允许远程进行。
Server的相关属性:
"htmlcode">
<Service name="Catalina"> </Service>
Service相关的属性:
"htmlcode">
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="4"/>
其中该组件的属性有:
"htmlcode">
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
4.4 连接器connector
连接器用于接收客户端发送的请求并返回响应给客户端。一个service中可以有多个connector。有多种connector,常见的为http/1.1,http/2和ajp(apache jserv protocol)。在tomcat中,ajp连接协议类型专用于tomcat前端是apache反向代理的情况下。
因此tomcat可以扮演两种角色:
1.Tomcat仅作为应用程序服务器:请求来自于前端的web服务器,这可能是Apache, IIS, Nginx等;
2.Tomcat既作为web服务器,也作为应用程序服务器:请求来自于浏览器。
Tomcat应该考虑工作情形并为相应情形下的请求分别定义好需要的连接器才能正确接收来自于客户端的请求。
此处暂先介绍HTTP/1.1连接器的属性设置。ajp后文再做介绍。
HTTP连接器表示支持HTTP/1.1协议的组件。设置了该连接器就表示catalina启用它的独立web服务功能,当然,肯定也提供它必须的servlets和jsp执行功能。在一个service中可以配置一个或多个连接器,每个连接器都可以将请求转发给它们相关联的engine以处理请求、创建响应。
如果想要配置某个web server的连接器,则使用AJP协议。
每个流入的请求都需要一个独立的线程来接收。当并发请求数量超出maxThreads指定的值时,多出的请求将被堆叠在套接字中,直到超出acceptCount指定的值。超出accpetCount的请求将以"connection refused"错误进行拒绝。
默认的定义如下:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
HTTP连接器的属性实在太多,详细配置方法见官方手册。通常定义HTTP连接器时必须定义的属性只有"port"。
"htmlcode">
<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" />
4.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属性有:
"htmlcode">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> </Host>
常用属性说明:
"*.a.com"。使用了星号前缀的虚拟主机的匹配优先级低于精确名称的虚拟主机。
"htmlcode">
<Host name="web.a.com" appBase="webapps" unpackWARs="true"> <Alias>www.a.com</Alias> </Host>
自动部署指的是自动装载webapp以提供相关webapp的服务。
4.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也是由此推断出来的。规则如下:
"/"后的路径,且所有"/"替换为"#"。
"htmlcode">
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容器中可以定义非常多的属性,详细内容见官方手册,以下是常见的几个属性:
""时,表示默认的context;另外只有在server.xml中才需要定义该属性,其他所有情况下都不能定义该属性,因为会根据docBase和context的xml文件名推断出path。
"htmlcode">
<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" />
4.9 被嵌套类valve
Valve中文意思是阀门,类似于过滤器,它可以工作于Engine和Host/Context之间、Host和Context之间以及Context和Web应用程序的某资源之间。一个容器内可以建立多个Valve,而且Valve定义的次序也决定了它们生效的次序。
有多种不同的Valve:
"htmlcode">
<Context privileged="true" path="/probe" docBase="probe"> <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.0\.0\.1"/> </Context>
其中相关属性定义有:
".valves.RemoteHostValve"或".valves.RemoteAddrValve";
"htmlcode">
<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配置文件server.xml详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。