Tomcat 是一个 HTTP server。同时,它也是一个 serverlet 容器,可以执行 java 的 Servlet,也可以把 JavaServer Pages(JSP)和 JavaServerFaces(JSF)编译成 Java Servlet。它的模型图如下:
给个生产环境 server.xml 的例子:
1<?xml version='1.0' encoding='utf-8'?>
2<Server port="-1" shutdown="SHUTDOWN">
3 <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
4 <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
5 <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
6 <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
7 <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
8
9 <GlobalNamingResources>
10 <Resource name="UserDatabase" auth="Container"
11 type="org.apache.catalina.UserDatabase"
12 description="User database that can be updated and saved"
13 factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
14 pathname="conf/tomcat-users.xml" />
15 </GlobalNamingResources>
16
17 <Service name="Catalina">
18 <Connector port="8080"
19 server="www.rendoumi.com"
20 protocol="org.apache.coyote.http11.Http11NioProtocol"
21 maxHttpHeaderSize="8192"
22 acceptCount="500"
23 maxThreads="1000"
24 minSpareThreads="200"
25 enableLookups="false"
26 redirectPort="8443"
27 connectionTimeout="20000"
28 relaxedQueryChars="[]|{}@!$*()+'.,;^\`"<>"
29 disableUploadTimeout="true"
30 allowTrace="false"
31 URIEncoding="UTF-8"
32 useBodyEncodingForURI="true" />
33
34 <Engine name="Catalina" defaultHost="localhost">
35 <Realm className="org.apache.catalina.realm.LockOutRealm">
36 <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
37 resourceName="UserDatabase"/>
38 </Realm>
39 <Host name="localhost" appBase="webapps" unpackWARs="false" autoDeploy="false">
40 <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="access_log." suffix=".txt"
41 fileDateFormat="yyyy-MM-dd"
42 pattern="%a|%A|%T|%{X-Forwarded-For}i|%l|%u|%t|%r|%s|%b|%{Referer}i|%{User-Agent}i " resolveHosts="false"/>
43 <Context path="" docBase="/export/servers/tomcat/webapps/web" />
44 </Host>
45
46 </Engine>
47 </Service>
48</Server>
分解开来一部分一部分的看:
Server
Server
第2行,是最大且必须唯一的组件。表示一个 Tomcat 的实例,它可以包含多个 Services,而每个 Service 都可以有自己的 Engine 和 connectors。
1<Server port="8005" shutdown="SHUTDOWN"> ...... </Server>
注意上面,我们把缺省的 port=“8005” 改成了 “-1”,这样防止从8005重启,避免安全问题。
Listeners
一个 Server
容器拥有若干 Listeners
(行 3-7)。一个 Listener
监听并回应特定的事件.
-
例如 GlobalResourcesLifecycleListener 就设置了 global resources,这样就可以使用 JNDI 来存取像数据库这种资源。
1<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 中加载上来的用户认证数据。
1<GlobalNamingResources>
2 <Resource name="UserDatabase" auth="Container"
3 type="org.apache.catalina.UserDatabase"
4 description="User database that can be updated and saved"
5 factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
6 pathname="conf/tomcat-users.xml" />
7</GlobalNamingResources>
我们可以再定义一个 Mysql 之类的 JNDI 来保存 mysql 数据库连接信息,用来实现连接池
Services
Service
用来关联多个 Connectors
到 Engine
。缺省的配置是配了一个 叫做 Catalina
的 Service
,Catalinna 缺省配了两个 Connectors,一个是8080的HTTP,一个是8009的AJP。
1<Service name="Catalina">
2 <Connector port="8080" protocol="HTTP/1.1"
3 connectionTimeout="20000"
4 redirectPort="8443" />
5 <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
6</Service>
注意最上面的配置,我们取消了8009的AJP,这个协议现在基本没人用,取消掉也避免安全问题。
下面给出一个 SSL 8443 的 connectors 的例子
1 <Connector port="8443" maxHttpHeaderSize="8192" SSLEnabled="true" server="Rendoumi"
2 maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
3 enableLookups="false" disableUploadTimeout="true"
4 acceptCount="100" scheme="https" secure="true" clientAuth="false"
5 URIEncoding="UTF-8"
6 sslProtocol="SSL"
7 ciphers="SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA"
8 keystoreFile="/export/servers/tomcat/rendoumi.keystore"
9 keystorePass="Fuck2020" />
Containers 概念
Tomcat 的容器概念,Tomcat认为 Engine
, Host
, Context
和 Cluster
处在同一个容器中. 最顶层的是 Engine
; 最底层是Context
。
另外像 Realm
和 Valve
,也可以放在容器中
Engine
Engine
是容器的顶端,可以包含有若干 Hosts
。我们可以配置 tomcat 服务多个虚拟主机。下面配置就是服务本机的一个服务。
1<Engine name="Catalina" defaultHost="localhost">
Catalina Engine
从 HTTP connector 处接收到客户端的 HTTP 请求,根据请求头中 Host: xxx 的内容,把请求路由到某个具体的 Host上。
Realm
Realm
本质是一个数据库,是用来保存用户名、密码、认证角色的东西。
1<Realm className="org.apache.catalina.realm.LockOutRealm">
2 <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
3</Realm>
Hosts
Host
定义了虚拟主机,可以定义多个虚拟主机。其中 appBase 千万不能为空,否则就可以读到 tomcat 的所有文件,就出线上事故大 Bug 了!!!
1<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
我们最上面的生产配置,不自解压,也不自动部署。
Valve
Valve
是用来拦截 HTTP requests的,做预处理后再交给下一个组件,它能在 Engine
, Host
, Context
中被定义。下面的例子就是在 Engine 中做了拦截,定义了日志格式,交给下一个日志处理组件做处理。
缺省配置
1<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
2 prefix="localhost_access_log." suffix=".txt"
3 pattern="%h %l %u %t "%r" %s %b" />
我们的配置修改了缺省的日志格式,多了很多明细的内容,改变了分割符:
1<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
2 prefix="access_log." suffix=".txt"
3 fileDateFormat="yyyy-MM-dd"
4 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 不同为空!!!
1<Context path="" docBase="/export/servers/tomcat/webapps/web" />
如上,我们就配好了一个生产环境的 server.xml ,注意,这个 xml 文件是可以放在解开的tomcat压缩包 apache-tomcat-8.5.64 目录之外的。
我们再另外编写一个启动文件 start.sh:
1#!/bin/sh
2export 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"
3export CATALINA_HOME=/export/servers/tomcat/apache-tomcat-8.5.64
4
5cd /export/servers/tomcat/
6$CATALINA_HOME/bin/catalina.sh start -config "/export/servers/tomcat/server.xml"
这样,我们的启动文件和配置文件,就和 tomcat 目录分离了,这样做的好处是如果 tomcat 需要升级,那么直接解压换目录即可。
我们可以做个软链接 tomcat 链接到 apache-tomcat-8.5.64,这样更方便操作。