Tomcat的server.xml是整个容器最核心的配置文件,它用XML格式描述了服务器启动时要构造的组件树。理解这份文件,是排查启动异常和性能瓶颈的前提。

一、Server与Service节点
最外层的<Server>代表一个Tomcat实例,它只能有一个,并且通常绑定一个关闭端口用于接收SHUTDOWN命令。在<Server>内部可以配置一个或多个<Service>,每个Service逻辑上把连接器和处理引擎绑在一起。
很多初学者误以为多写几个Service就能隔离应用,实际上它们共享同一个JVM和类加载体系。如果只是为了部署不同应用,更推荐在Engine下用多个<Host>或<Context>实现。下面是一段最简化的结构示例:
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps" />
</Engine>
</Service>
</Server>
从上面的代码可以看出,Service只是一个中间层,真正干活的是Connector和Engine。修改Service的name不会影响请求处理,但会在日志中作为标识出现,方便区分多个服务。
二、Connector连接器配置
Connector是Tomcat对外暴露的协议入口,常见的有HTTP/1.1和AJP。以HTTP连接器为例,除了port和protocol,还有connectionTimeout、maxThreads、acceptCount等参数直接决定并发能力。
connectionTimeout默认是20000毫秒,表示客户端连接后多久不发送请求就断开。maxThreads是处理请求的最大线程数,如果接口耗时较长还遇上流量高峰,这个值设太小会大量丢请求。下面的配置展示了带线程池和压缩的写法:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
maxThreads="200"
minSpareThreads="20"
acceptCount="100"
compression="on"
compressableMimeType="text/html,text/xml,text/plain" />
需要注意,protocol写成HTTP/1.1时Tomcat会自动选用NIO实现,若写org.apache.coyote.http11.Http11Nio2Protocol则是NIO2。选错协议类会导致启动报错,而AJP连接器一般只在和前置Web服务器联动时才开启,裸跑时建议注释掉避免端口暴露。
2.1 常见Connector误区
有人把maxThreads当成最大并发用户数,其实它只是Tomcat工作线程上限。若后端数据库慢,线程全卡在等待,真实吞吐远小于线程数。此时应配合数据库连接池限流,而不是盲目调大maxThreads。
另一个坑是开了compression却没配compressableMimeType,默认只压缩少数类型,接口返回JSON若不在列表里就不会压缩,前端仍收到大报文。建议明确写出需要压缩的MIME类型。
三、Engine与Host虚拟主机
Engine是Service里的请求处理核心,它根据域名把请求派发到对应的Host。defaultHost指向当域名不匹配任何Host时使用的默认站点,写错会导致访问空白页。
Host的appBase指定应用目录,unpackWARs控制是否自动解压war包,autoDeploy控制是否监听目录变化热部署。生产环境通常把autoDeploy设为false,防止误传文件触发重启。示例配置如下:
<Engine name="Catalina" defaultHost="www.ipipp.com">
<Host name="www.ipipp.com" appBase="webapps"
unpackWARs="true" autoDeploy="false">
<Context path="" docBase="myapp" reloadable="false" />
</Host>
</Engine>
在Host内部可以用Context精确控制某个路径对应的目录或war。reloadable设true虽方便开发,但会周期性扫描类变动,生产环境务必关闭,否则CPU会被监控线程吃满。
3.1 多域名映射
同一个Tomcat可以通过多个Host响应不同域名,比如把静态站点和接口服务分开。只要DNS都解析到同一IP,Tomcat会根据HTTP头里的Host字段自动路由,不需要额外反向代理。
但这种做法的隔离性弱于多实例,某个Host的Context崩溃可能影响同Engine下其他Host。对稳定性要求高的系统,仍建议用多个Tomcat实例加Nginx分发。
四、嵌套组件与全局配置
除了上述主节点,server.xml里还能定义GlobalNamingResources和Realm。前者提供JNDI资源如数据库连接,后者做身份认证。它们位置在Server级,可被各Service引用。
例如通过Resource定义数据源,应用再用java:comp/env前缀查找,避免把账号密码写死在代码里。不过Spring Boot流行后,这种配置用得越来越少,更多是老项目维护时才碰得到。
<GlobalNamingResources>
<Resource name="jdbc/TestDB" auth="Container"
type="javax.sql.DataSource"
maxTotal="20" maxIdle="5" maxWaitMillis="10000"
username="root" password="root"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/test" />
</GlobalNamingResources>
Realm常配合Manager应用做后台保护,但若不需要Tomcat自带管理页面,直接删掉相关Host里的配置更干净,也减少攻击面。每次改完server.xml记得校验XML闭合,Tomcat启动失败大半是标签没配对。
五、修改后如何验证
配置完不要急着上线,先在本地执行startup.sh,看catalina.out里有没有严重错误。再用curl发几个请求,确认端口通、域名路由对、响应无乱码。
如果启动报LifecycleException,优先检查Connector的protocol类名和端口占用。用netstat -anp看端口状态,能省去很多猜测时间。养成备份原文件习惯,回滚只需覆盖即可。
Tomcatserver_xmlConnector修改时间:2026-08-07 12:21:33