Tomcat 是一个 HTTP server。同时,它也是一个 serverlet 容器,可以执行 java 的 Servlet,也可以把 JavaServer Pages(JSP)和 JavaServerFaces(JSF)编译成 Java Servlet。它的模型图如下:

给个生产环境 server.xml 的例子:
| |
分解开来一部分一部分的看:
Server
Server 第2行,是最大且必须唯一的组件。表示一个 Tomcat 的实例,它可以包含多个 Services,而每个 Service 都可以有自己的 Engine 和 connectors。
<Server port="8005" shutdown="SHUTDOWN"> ...... </Server>
注意上面,我们把缺省的 port=“8005” 改成了 “-1”,这样防止从8005重启,避免安全问题。
Listeners
一个 Server 容器拥有若干 Listeners (行 3-7)。一个 Listener 监听并回应特定的事件.
例如 GlobalResourcesLifecycleListener 就设置了 global resources,这样就可以使用 JNDI 来存取像数据库这种资源。
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
Global Naming Resources
<GlobalNamingResources> (行 9-15) 定义了 JNDI (Java Naming and Directory Interface) 资源,这个是 LDAP 的东西,允许 java 软件通过目录发现对象和属性值。
缺省定义了一个 UserDatabase 的 JNDI 资源(行 10-14),这个对象其实是一个内存数据库,保存着从 conf/tomcat-users.xml 中加载上来的用户认证数据。
<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>
我们可以再定义一个 Mysql 之类的 JNDI 来保存 mysql 数据库连接信息,用来实现连接池
Services
Service 用来关联多个 Connectors 到 Engine。缺省的配置是配了一个 叫做 Catalina 的 Service ,Catalinna 缺省配了两个 Connectors,一个是8080的HTTP,一个是8009的AJP。
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
</Service>
注意最上面的配置,我们取消了8009的AJP,这个协议现在基本没人用,取消掉也避免安全问题。
下面给出一个 SSL 8443 的 connectors 的例子
<Connector port="8443" maxHttpHeaderSize="8192" SSLEnabled="true" server="Rendoumi"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true" clientAuth="false"
URIEncoding="UTF-8"
sslProtocol="SSL"
ciphers="SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA"
keystoreFile="/export/servers/tomcat/rendoumi.keystore"
keystorePass="Fuck2020" />
Containers 概念
Tomcat 的容器概念,Tomcat认为 Engine, Host, Context 和 Cluster处在同一个容器中. 最顶层的是 Engine; 最底层是Context。
另外像 Realm 和 Valve,也可以放在容器中
Engine
Engine 是容器的顶端,可以包含有若干 Hosts。我们可以配置 tomcat 服务多个虚拟主机。下面配置就是服务本机的一个服务。
<Engine name="Catalina" defaultHost="localhost">
Catalina Engine 从 HTTP connector 处接收到客户端的 HTTP 请求,根据请求头中 Host: xxx 的内容,把请求路由到某个具体的 Host上。
Realm
Realm 本质是一个数据库,是用来保存用户名、密码、认证角色的东西。
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
</Realm>
Hosts
Host 定义了虚拟主机,可以定义多个虚拟主机。其中 appBase 千万不能为空,否则就可以读到 tomcat 的所有文件,就出线上事故大 Bug 了!!!
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
我们最上面的生产配置,不自解压,也不自动部署。
Valve
Valve 是用来拦截 HTTP requests的,做预处理后再交给下一个组件,它能在 Engine, Host, Context 中被定义。下面的例子就是在 Engine 中做了拦截,定义了日志格式,交给下一个日志处理组件做处理。
缺省配置
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
我们的配置修改了缺省的日志格式,多了很多明细的内容,改变了分割符:
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="access_log." suffix=".txt"
fileDateFormat="yyyy-MM-dd"
pattern="%a|%A|%T|%{X-Forwarded-For}i|%l|%u|%t|%r|%s|%b|%{Referer}i|%{User-Agent}i " resolveHosts="false"/>
Context
Context定义了具体的访问路径,一定要指定 docBase !!!大家一定要记住 appBase 和 docBase 不同为空!!!
<Context path="" docBase="/export/servers/tomcat/webapps/web" />
如上,我们就配好了一个生产环境的 server.xml ,注意,这个 xml 文件是可以放在解开的tomcat压缩包 apache-tomcat-8.5.64 目录之外的。
我们再另外编写一个启动文件 start.sh:
#!/bin/sh
export JAVA_OPTS="-server -Xms1024m -Xmx2048m -Djava.awt.headless=true -Dsun.net.client.defaultConnectTimeout=60000 -Dsun.net.client.defaultReadTimeout=60000 -Djmagick.systemclassloader=no -Dnetworkaddress.cache.ttl=300 -Dsun.net.inetaddr.ttl=300"
export CATALINA_HOME=/export/servers/tomcat/apache-tomcat-8.5.64
cd /export/servers/tomcat/
$CATALINA_HOME/bin/catalina.sh start -config "/export/servers/tomcat/server.xml"
这样,我们的启动文件和配置文件,就和 tomcat 目录分离了,这样做的好处是如果 tomcat 需要升级,那么直接解压换目录即可。
我们可以做个软链接 tomcat 链接到 apache-tomcat-8.5.64,这样更方便操作。