Tomcat 服务器配置详解
Server Configuration
概述
Tomcat的server.xml是核心配置文件,定义了服务器的整体架构和行为。本文将深入解析server.xml的各个组件配置,包括Service、Engine、Host、Context等关键元素的详细配置方法。
1. server.xml文件结构
1.1 配置文件层次结构
<Server> <!-- 服务器根元素 -->
<GlobalNamingResources> <!-- 全局JNDI资源 -->
</GlobalNamingResources>
<Service> <!-- 服务定义 -->
<Connector> <!-- 连接器 -->
</Connector>
<Engine> <!-- 引擎 -->
<Realm> <!-- 认证领域 -->
</Realm>
<Host> <!-- 虚拟主机 -->
<Context> <!-- 上下文 -->
</Context>
<Valve> <!-- 阀门 -->
</Valve>
</Host>
</Engine>
</Service>
</Server>
1.2 配置文件备份策略
#!/bin/bash
# backup-server-config.sh
CATALINA_HOME="/opt/tomcat9"
BACKUP_DIR="/var/backups/tomcat"
DATE=$(date +%Y%m%d_%H%M%S)
# 创建备份目录
mkdir -p $BACKUP_DIR
# 备份server.xml和相关配置
cp $CATALINA_HOME/conf/server.xml $BACKUP_DIR/server.xml.$DATE
cp $CATALINA_HOME/conf/web.xml $BACKUP_DIR/web.xml.$DATE
cp $CATALINA_HOME/conf/context.xml $BACKUP_DIR/context.xml.$DATE
cp $CATALINA_HOME/conf/tomcat-users.xml $BACKUP_DIR/tomcat-users.xml.$DATE
echo "配置文件已备份到: $BACKUP_DIR"
# 保留最近10个备份
find $BACKUP_DIR -name "*.xml.*" -type f | sort | head -n -40 | xargs rm -f
2. Server元素配置
2.1 基础Server配置
<Server port="8005"
shutdown="SHUTDOWN"
address="127.0.0.1">
<!-- 服务器监听器 -->
<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" />
<!-- 全局JNDI资源定义 -->
<GlobalNamingResources>
<!-- 用户数据库 -->
<Resource name="UserDatabase"
auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database for authentication"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
<!-- 数据库连接池 -->
<Resource name="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/myapp?useSSL=false&serverTimezone=Asia/Shanghai"
username="dbuser"
password="dbpass"
maxTotal="20"
maxIdle="10"
maxWaitMillis="10000"
validationQuery="SELECT 1"
testOnBorrow="true"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="30000"
minEvictableIdleTimeMillis="60000" />
<!-- 邮件会话 -->
<Resource name="mail/Session"
auth="Container"
type="javax.mail.Session"
mail.smtp.host="smtp.example.com"
mail.smtp.port="587"
mail.smtp.auth="true"
mail.smtp.starttls.enable="true"
username="noreply@example.com"
password="mailpass" />
</GlobalNamingResources>
</Server>
2.2 高级Server配置
<Server port="8005"
shutdown="SECURE_SHUTDOWN_STRING"
address="127.0.0.1"
className="org.apache.catalina.core.StandardServer">
<!-- 自定义服务器监听器 -->
<Listener className="com.example.CustomServerLifecycleListener" />
<!-- JMX远程监控配置 -->
<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener"
rmiRegistryPortPlatform="9999"
rmiServerPortPlatform="9998"
useLocalPorts="false" />
<!-- 性能监控监听器 -->
<Listener className="org.apache.catalina.startup.VersionLoggerListener"
logArgs="true"
logEnv="true"
logProps="true" />
</Server>
3. Service元素配置
3.1 基础Service配置
<Service name="Catalina">
<!-- HTTP连接器 -->
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="200"
minSpareThreads="10"
maxSpareThreads="75"
enableLookups="false"
compression="on"
compressionMinSize="2048"
compressibleMimeType="text/html,text/xml,text/css,application/javascript,application/json"
URIEncoding="UTF-8" />
<!-- HTTPS连接器 -->
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true"
compression="on">
<SSLHostConfig>
<Certificate certificateKeystoreFile="conf/keystore.jks"
certificateKeystorePassword="changeit"
type="RSA" />
</SSLHostConfig>
</Connector>
<!-- AJP连接器(用于与Apache集成) -->
<Connector port="8009"
protocol="AJP/1.3"
redirectPort="8443"
secretRequired="false"
address="0.0.0.0" />
<!-- 引擎配置 -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
<!-- Engine内容在下一节详述 -->
</Engine>
</Service>
3.2 多Service配置
<!-- 主服务 - 生产应用 -->
<Service name="Production">
<Connector port="8080" protocol="HTTP/1.1" />
<Engine name="ProductionEngine" defaultHost="app.example.com">
<Host name="app.example.com" appBase="webapps">
<!-- 生产应用配置 -->
</Host>
</Engine>
</Service>
<!-- 管理服务 - 管理界面 -->
<Service name="Management">
<Connector port="8081" protocol="HTTP/1.1" />
<Engine name="ManagementEngine" defaultHost="admin.example.com">
<Host name="admin.example.com" appBase="admin-webapps">
<!-- 管理应用配置 -->
</Host>
</Engine>
</Service>
4. Engine元素配置
4.1 基础Engine配置
<Engine name="Catalina"
defaultHost="localhost"
jvmRoute="node1">
<!-- 认证领域配置 -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<!-- 数据库认证领域 -->
<Realm className="org.apache.catalina.realm.DataSourceRealm"
dataSourceName="jdbc/AuthDB"
userTable="users"
userNameCol="username"
userCredCol="password"
userRoleTable="user_roles"
roleNameCol="role_name" />
</Realm>
<!-- 集群配置(如果启用集群) -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
<!-- 集群配置详见集群章节 -->
</Cluster>
<!-- 虚拟主机配置 -->
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<!-- Host配置在下一节详述 -->
</Host>
</Engine>
4.2 多域名Engine配置
<Engine name="Catalina" defaultHost="www.example.com">
<!-- 组合认证领域 -->
<Realm className="org.apache.catalina.realm.CombinedRealm">
<!-- LDAP认证 -->
<Realm className="org.apache.catalina.realm.JNDIRealm"
connectionURL="ldap://ldap.example.com:389"
userPattern="uid={0},ou=people,dc=example,dc=com"
roleBase="ou=groups,dc=example,dc=com"
roleName="cn"
roleSearch="(member={0})" />
<!-- 数据库认证(备用) -->
<Realm className="org.apache.catalina.realm.DataSourceRealm"
dataSourceName="jdbc/UserDB"
userTable="users"
userNameCol="username"
userCredCol="password"
userRoleTable="user_roles"
roleNameCol="role_name" />
</Realm>
<!-- 主域名 -->
<Host name="www.example.com" appBase="webapps" />
<!-- API域名 -->
<Host name="api.example.com" appBase="api-webapps" />
<!-- 静态资源域名 -->
<Host name="static.example.com" appBase="static-webapps" />
</Engine>
5. Host元素配置
5.1 基础Host配置
<Host name="localhost"
appBase="webapps"
unpackWARs="true"
autoDeploy="true"
deployOnStartup="true"
createDirs="true">
<!-- 访问日志阀门 -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b %D "%{Referer}i" "%{User-Agent}i""
rotatable="true"
renameOnRotate="true"
maxDays="30" />
<!-- 错误报告阀门 -->
<Valve className="org.apache.catalina.valves.ErrorReportValve"
showReport="false"
showServerInfo="false" />
<!-- 默认上下文 -->
<Context path="" docBase="ROOT" reloadable="false">
<!-- 资源链接 -->
<ResourceLink name="jdbc/MyDB"
global="jdbc/MyDB"
type="javax.sql.DataSource" />
</Context>
</Host>
5.2 生产环境Host配置
<Host name="app.example.com"
appBase="webapps"
unpackWARs="false"
autoDeploy="false"
deployOnStartup="true">
<!-- 域名别名 -->
<Alias>example.com</Alias>
<Alias>www.app.example.com</Alias>
<!-- 高级访问日志 -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="app_access_log"
suffix=".txt"
pattern='%h %l %u %t "%r" %s %b %D "%{Referer}i" "%{User-Agent}i" %{X-Forwarded-For}i'
rotatable="true"
buffered="false"
requestAttributesEnabled="true" />
<!-- 远程IP阀门(用于负载均衡环境) -->
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="X-Forwarded-For"
remoteIpProxiesHeader="X-Forwarded-By"
trustedProxies="192\.168\.1\..*|127\.0\.0\.1" />
<!-- 限流阀门 -->
<Valve className="org.apache.catalina.valves.SemaphoreValve"
concurrency="100"
fairness="true"
block="true" />
<!-- 应用上下文 -->
<Context path=""
docBase="/opt/apps/myapp.war"
reloadable="false"
crossContext="false"
swallowOutput="true">
<!-- 数据源配置 -->
<Resource name="jdbc/AppDB"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://db.example.com:3306/appdb"
username="appuser"
password="encrypted:abcd1234"
maxActive="100"
maxIdle="30"
maxWait="10000"
initialSize="10"
validationQuery="SELECT 1"
testOnBorrow="true"
testOnReturn="false"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="30000"
numTestsPerEvictionRun="3"
minEvictableIdleTimeMillis="60000"
removeAbandoned="true"
removeAbandonedTimeout="60"
logAbandoned="true"
jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer" />
<!-- 环境变量 -->
<Environment name="app.env"
value="production"
type="java.lang.String" />
<Environment name="app.debug"
value="false"
type="java.lang.Boolean" />
</Context>
</Host>
6. Valve配置详解
6.1 访问控制Valve
<!-- IP访问控制 -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="192\.168\.1\..*|127\.0\.0\.1"
deny=".*" />
<!-- 主机名访问控制 -->
<Valve className="org.apache.catalina.valves.RemoteHostValve"
allow=".*\.example\.com|localhost"
deny=".*\.malicious\.com" />
<!-- 时间访问控制 -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
pattern="%h %l %u %t "%r" %s %b"
condition="!skipLogging" />
6.2 自定义Valve
// CustomSecurityValve.java
package com.example.valve;
import org.apache.catalina.valves.ValveBase;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import javax.servlet.ServletException;
import java.io.IOException;
public class CustomSecurityValve extends ValveBase {
private String allowedUserAgents = ".*";
private String blockedUserAgents = "";
private int maxRequestsPerMinute = 100;
@Override
public void invoke(Request request, Response response)
throws IOException, ServletException {
// 检查User-Agent
String userAgent = request.getHeader("User-Agent");
if (userAgent != null && !userAgent.matches(allowedUserAgents)) {
response.sendError(403, "Forbidden User Agent");
return;
}
if (userAgent != null && !blockedUserAgents.isEmpty()
&& userAgent.matches(blockedUserAgents)) {
response.sendError(403, "Blocked User Agent");
return;
}
// 限流检查
String clientIP = request.getRemoteAddr();
if (isRateLimited(clientIP)) {
response.sendError(429, "Too Many Requests");
return;
}
// 调用下一个Valve
getNext().invoke(request, response);
}
private boolean isRateLimited(String clientIP) {
// 实现限流逻辑
// 可以使用Redis或内存缓存来跟踪请求频率
return false;
}
// Getter和Setter方法
public void setAllowedUserAgents(String allowedUserAgents) {
this.allowedUserAgents = allowedUserAgents;
}
public void setBlockedUserAgents(String blockedUserAgents) {
this.blockedUserAgents = blockedUserAgents;
}
public void setMaxRequestsPerMinute(int maxRequestsPerMinute) {
this.maxRequestsPerMinute = maxRequestsPerMinute;
}
}
配置自定义Valve:
<Valve className="com.example.valve.CustomSecurityValve"
allowedUserAgents="Mozilla.*|Chrome.*"
blockedUserAgents=".*bot.*|.*crawler.*"
maxRequestsPerMinute="60" />
7. Context配置详解
7.1 应用Context配置
<Context path="/myapp"
docBase="/opt/apps/myapp"
reloadable="false"
crossContext="false"
privileged="false"
allowLinking="false"
swallowOutput="true"
sessionCookieName="JSESSIONID"
sessionCookiePath="/"
sessionCookieMaxAge="-1"
sessionTimeout="30">
<!-- 应用参数 -->
<Parameter name="app.name" value="MyApplication" />
<Parameter name="app.version" value="1.0.0" />
<!-- 环境变量 -->
<Environment name="jdbc/maxConnections"
value="100"
type="java.lang.Integer" />
<!-- 资源配置 -->
<Resource name="jdbc/AppDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/appdb"
username="appuser"
password="apppass"
maxTotal="20"
maxIdle="10"
maxWaitMillis="10000" />
<!-- 事务配置 -->
<Transaction factory="org.apache.catalina.core.DefaultTransactionFactory" />
<!-- Web资源集合 -->
<Resources>
<PreResources className="org.apache.catalina.webresources.DirResourceSet"
webAppMount="/WEB-INF/lib"
base="/opt/shared-libs" />
</Resources>
<!-- 管理器配置 -->
<Manager className="org.apache.catalina.session.PersistentManager"
saveOnRestart="true"
maxActiveSession="-1"
minIdleSwap="10"
maxIdleSwap="20"
maxIdleBackup="5">
<Store className="org.apache.catalina.session.FileStore"
directory="/opt/tomcat/sessions" />
</Manager>
</Context>
7.2 安全Context配置
<Context path="/secure-app"
docBase="/opt/secure-apps/secure-app"
reloadable="false"
privileged="true"
allowLinking="false">
<!-- 安全约束 -->
<Realm className="org.apache.catalina.realm.DataSourceRealm"
dataSourceName="jdbc/AuthDB"
userTable="users"
userNameCol="username"
userCredCol="password"
userRoleTable="user_roles"
roleNameCol="role_name"
digest="SHA-256" />
<!-- 访问控制 -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="192\.168\.1\..*" />
<!-- HTTPS重定向 -->
<Valve className="org.apache.catalina.valves.SSLValve" />
<!-- 安全头 -->
<Valve className="org.apache.catalina.valves.HttpHeaderSecurityFilter"
hstsMaxAgeSeconds="31536000"
hstsIncludeSubdomains="true"
antiClickJackingEnabled="true"
antiClickJackingOption="SAMEORIGIN"
blockContentTypeSniffingEnabled="true" />
</Context>
8. 全局配置管理
8.1 配置模板化
#!/bin/bash
# generate-server-xml.sh
ENV=${1:-development}
TEMPLATE_DIR="/opt/tomcat/config-templates"
OUTPUT_FILE="/opt/tomcat/conf/server.xml"
case $ENV in
"development")
HTTP_PORT=8080
HTTPS_PORT=8443
AJP_PORT=8009
DEBUG_ENABLED=true
;;
"staging")
HTTP_PORT=8080
HTTPS_PORT=8443
AJP_PORT=8009
DEBUG_ENABLED=false
;;
"production")
HTTP_PORT=80
HTTPS_PORT=443
AJP_PORT=8009
DEBUG_ENABLED=false
;;
esac
# 使用envsubst替换变量
envsubst < "$TEMPLATE_DIR/server.xml.template" > "$OUTPUT_FILE"
echo "生成配置文件: $OUTPUT_FILE (环境: $ENV)"
8.2 配置验证脚本
#!/bin/bash
# validate-config.sh
CATALINA_HOME="/opt/tomcat9"
CONFIG_FILE="$CATALINA_HOME/conf/server.xml"
echo "=== Tomcat配置验证 ==="
# 检查XML语法
if xmllint --noout "$CONFIG_FILE" 2>/dev/null; then
echo "✓ XML语法正确"
else
echo "✗ XML语法错误"
xmllint "$CONFIG_FILE"
exit 1
fi
# 检查Tomcat配置
if $CATALINA_HOME/bin/catalina.sh configtest; then
echo "✓ Tomcat配置正确"
else
echo "✗ Tomcat配置错误"
exit 1
fi
# 检查端口占用
PORTS=("8080" "8443" "8005" "8009")
for port in "${PORTS[@]}"; do
if netstat -tuln | grep ":$port " > /dev/null; then
echo "⚠ 端口 $port 已被占用"
else
echo "✓ 端口 $port 可用"
fi
done
# 检查Java版本兼容性
JAVA_VERSION=$(java -version 2>&1 | head -n 1 | cut -d'"' -f2)
echo "✓ Java版本: $JAVA_VERSION"
# 检查内存设置
if [ -f "$CATALINA_HOME/bin/setenv.sh" ]; then
echo "✓ 找到JVM参数配置文件"
grep -E "Xms|Xmx" "$CATALINA_HOME/bin/setenv.sh"
else
echo "⚠ 未找到JVM参数配置文件"
fi
echo "=== 配置验证完成 ==="
9. 动态配置管理
9.1 JMX配置管理
// ConfigurationManager.java
package com.example.tomcat.management;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
public class ConfigurationManager {
private MBeanServer mbs;
public ConfigurationManager() {
this.mbs = ManagementFactory.getPlatformMBeanServer();
}
public void updateConnectorMaxThreads(String serviceName,
String connectorPort,
int maxThreads) throws Exception {
ObjectName connectorName = new ObjectName(
"Catalina:type=Connector,service=" + serviceName + ",port=" + connectorPort
);
mbs.setAttribute(connectorName,
new javax.management.Attribute("maxThreads", maxThreads));
System.out.println("连接器最大线程数已更新为: " + maxThreads);
}
public void updateDataSourceSettings(String contextPath,
String resourceName,
int maxTotal) throws Exception {
ObjectName resourceName = new ObjectName(
"Catalina:type=Resource,resourcetype=Global,class=javax.sql.DataSource,name=\""
+ resourceName + "\""
);
mbs.setAttribute(resourceName,
new javax.management.Attribute("maxTotal", maxTotal));
System.out.println("数据源最大连接数已更新为: " + maxTotal);
}
public String getServerInfo() throws Exception {
ObjectName serverName = new ObjectName("Catalina:type=Server");
return (String) mbs.getAttribute(serverName, "serverInfo");
}
}
9.2 配置热重载
#!/bin/bash
# reload-config.sh
CATALINA_HOME="/opt/tomcat9"
CONFIG_FILE="$CATALINA_HOME/conf/server.xml"
BACKUP_FILE="$CONFIG_FILE.backup.$(date +%Y%m%d_%H%M%S)"
# 备份当前配置
cp "$CONFIG_FILE" "$BACKUP_FILE"
# 验证新配置
if ! $CATALINA_HOME/bin/catalina.sh configtest; then
echo "配置验证失败,恢复备份"
cp "$BACKUP_FILE" "$CONFIG_FILE"
exit 1
fi
# 发送信号重新加载配置(需要自定义监听器支持)
TOMCAT_PID=$(ps aux | grep catalina | grep -v grep | awk '{print $2}')
if [ ! -z "$TOMCAT_PID" ]; then
kill -USR1 $TOMCAT_PID
echo "已发送配置重载信号到进程: $TOMCAT_PID"
else
echo "Tomcat进程未找到,需要重启服务"
systemctl restart tomcat
fi
小结
通过本文学习,你应该掌握:
- server.xml文件的完整结构和层次关系
- Server、Service、Engine、Host、Context各元素的详细配置
- Valve组件的使用和自定义开发
- JNDI资源的配置和管理
- 安全配置和访问控制
- 配置文件的模板化和验证
- 动态配置管理和热重载技术
下一篇文章将详细介绍Tomcat连接器的配置与优化。