Spring Boot 定制化内置 Tomcat 详解:1.x 与 2.x+ 版本适配指南
Spring Boot 内置的 Tomcat 容器虽提供默认配置,但实际开发中常需定制化调整(如修改端口、编码、线程池、 session 超时等)。不同 Spring Boot 版本(1.x 与 2.x+)提供的定制化接口存在差异,核心是从 EmbeddedServletContainerCustomizer(1.x)演进为 WebServerFactoryCustomizer(2.x+)。从 “1.x 版本定制→2.x+ 版本定制→核心配置场景→实战示例” 四个维度,系统讲解内置 Tomcat 的定制方法,帮你跨版本适配容器配置需求。
核心背景:版本演进与接口差异
Spring Boot 2.x 对内置服务器(Tomcat/Jetty/Undertow)的抽象层进行了重构,核心变化是将 “嵌入式 Servlet 容器” 的概念升级为 “Web 服务器”,对应的定制化接口也随之调整:
| Spring Boot 版本 |
核心定制化接口 |
对应的 Tomcat 工厂类 |
适用场景 |
| 1.x 版本 |
EmbeddedServletContainerCustomizer |
TomcatEmbeddedServletContainerFactory |
1.x 版本定制内置 Tomcat |
| 2.x+ 版本 |
WebServerFactoryCustomizer |
TomcatServletWebServerFactory |
2.x+ 版本定制内置 Tomcat |
核心逻辑不变:均通过 “定制器接口” 获取 Tomcat 工厂类,再通过工厂类设置容器参数(如端口、编码、线程池)。
1.x 版本:基于 EmbeddedServletContainerCustomizer 定制
Spring Boot 1.x 中,通过实现 EmbeddedServletContainerCustomizer 接口,可获取 TomcatEmbeddedServletContainerFactory 工厂类,进而定制 Tomcat 配置。
1. 核心步骤
(1)实现 EmbeddedServletContainerCustomizer 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.stereotype.Component;
@Component public class Tomcat1xCustomizer implements EmbeddedServletContainerCustomizer {
@Override public void customize(org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer container) { TomcatEmbeddedServletContainerFactory tomcatFactory = (TomcatEmbeddedServletContainerFactory) container;
tomcatFactory.setSessionTimeout(300000);
tomcatFactory.setUriEncoding(java.nio.charset.StandardCharsets.UTF_8);
tomcatFactory.addConnectorCustomizers(connector -> { connector.setPort(8081); connector.setProtocol("org.apache.coyote.http11.Http11NioProtocol"); connector.setMaxConnections(1000); });
tomcatFactory.addEngineValves(valve -> { if (valve instanceof org.apache.catalina.valves.AccessLogValve) { org.apache.catalina.valves.AccessLogValve accessLogValve = (org.apache.catalina.valves.AccessLogValve) valve; accessLogValve.setPattern("%h %l %u %t \"%r\" %s %b"); accessLogValve.setDirectory("logs"); accessLogValve.setPrefix("tomcat-access-"); } }); } }
|
(2)生效方式
- 只需将定制器类标注
@Component(或通过 @Bean 注册),Spring Boot 会自动发现并执行 customize 方法;
- 配置优先级:代码定制的参数 低于 配置文件(如
server.port),若配置文件已设置,代码定制会被覆盖。
2. 1.x 版本关键 API 说明
| 工厂类方法 |
作用描述 |
示例值 |
setSessionTimeout(int) |
设置 session 超时时间(单位:毫秒) |
300000(5 分钟) |
setUriEncoding(Charset) |
设置 URI 编码(解决中文路径乱码) |
StandardCharsets.UTF_8 |
addConnectorCustomizers() |
定制 Tomcat 连接器(端口、协议、连接数) |
connector -> connector.setMaxConnections(1000) |
addEngineValves() |
定制 Tomcat 引擎(访问日志、安全 Valve) |
添加 AccessLogValve 记录请求日志 |
2.x+ 版本:基于 WebServerFactoryCustomizer 定制
Spring Boot 2.x+ 废弃了 EmbeddedServletContainerCustomizer,改用 WebServerFactoryCustomizer 接口,对应的 Tomcat 工厂类也从 TomcatEmbeddedServletContainerFactory 改为 TomcatServletWebServerFactory,但定制逻辑与 1.x 基本一致。
1. 核心步骤
(1)实现 WebServerFactoryCustomizer 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.stereotype.Component; import java.nio.charset.StandardCharsets;
@Component public class Tomcat2xCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override public void customize(ConfigurableServletWebServerFactory factory) { TomcatServletWebServerFactory tomcatFactory = (TomcatServletWebServerFactory) factory;
tomcatFactory.setUriEncoding(StandardCharsets.UTF_8);
tomcatFactory.addConnectorCustomizers(connector -> { org.apache.tomcat.util.threads.ThreadPoolExecutor executor = (org.apache.tomcat.util.threads.ThreadPoolExecutor) connector.getProtocolHandler().getExecutor(); if (executor != null) { executor.setCorePoolSize(10); executor.setMaximumPoolSize(100); executor.setKeepAliveTime(60, java.util.concurrent.TimeUnit.SECONDS); } });
tomcatFactory.setAccessLogEnabled(true); tomcatFactory.setAccessLogPattern("%h %l %u %t \"%r\" %s %b %D"); tomcatFactory.setAccessLogDirectory(new java.io.File("logs"));
tomcatFactory.addAdditionalTomcatConnectors(createSslConnector()); }
private org.apache.catalina.connector.Connector createSslConnector() { org.apache.catalina.connector.Connector connector = new org.apache.catalina.connector.Connector("org.apache.coyote.http11.Http11NioProtocol"); org.apache.tomcat.util.net.SSLHostConfig sslHostConfig = new org.apache.tomcat.util.net.SSLHostConfig(); org.apache.tomcat.util.net.SSLHostConfig.Certificate certificate = new org.apache.tomcat.util.net.SSLHostConfig.Certificate(); certificate.setCertificateKeystoreFile("classpath:ssl/localhost-ssl.jks"); certificate.setType("RSA"); certificate.setCertificateKeystorePassword("123456"); sslHostConfig.addCertificate(certificate); connector.addSslHostConfig(sslHostConfig); connector.setPort(8443); return connector; } }
|
(2)生效方式
2. 2.x+ 版本关键 API 新增特性
相比 1.x,2.x+ 的 TomcatServletWebServerFactory 新增了更便捷的 API,简化常见配置:
| 新增 API |
作用描述 |
示例 |
setAccessLogEnabled(boolean) |
快速开启 / 关闭访问日志 |
tomcatFactory.setAccessLogEnabled(true) |
setAccessLogPattern(String) |
设置访问日志格式 |
"%h %l %u %t \"%r\" %s %b" |
addAdditionalTomcatConnectors() |
新增额外连接器(如同时支持 HTTP 和 HTTPS) |
新增 8443 端口的 SSL 连接器 |
setContextPath(String) |
设置应用上下文路径(替代 1.x 的 setContextPath) |
tomcatFactory.setContextPath("/demo") |
核心定制场景实战(2.x+ 版本为例)
以下是内置 Tomcat 最常见的定制场景,基于 2.x+ 版本实现,覆盖编码、线程池、HTTPS、session 超时等需求。
场景 1:解决中文乱码(URI + 响应编码)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Component public class TomcatEncodingCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory factory) { factory.setUriEncoding(StandardCharsets.UTF_8);
factory.addConnectorCustomizers(connector -> { org.apache.coyote.http11.Http11NioProtocol protocol = (org.apache.coyote.http11.Http11NioProtocol) connector.getProtocolHandler(); protocol.setURIEncoding("UTF-8"); protocol.setUseBodyEncodingForURI(true); }); } }
|
场景 2:优化线程池(提升并发能力)
Tomcat 线程池参数直接影响应用的并发处理能力,需根据服务器 CPU 核心数合理配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @Component public class TomcatThreadPoolCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory factory) { factory.addConnectorCustomizers(connector -> { org.apache.tomcat.util.threads.ThreadPoolExecutor executor = (org.apache.tomcat.util.threads.ThreadPoolExecutor) connector.getProtocolHandler().getExecutor(); if (executor == null) { executor = new org.apache.tomcat.util.threads.ThreadPoolExecutor( 10, 100, 60, java.util.concurrent.TimeUnit.SECONDS, new java.util.concurrent.LinkedBlockingQueue<>(1000) ); executor.setThreadNamePrefix("tomcat-thread-"); connector.getProtocolHandler().setExecutor(executor); } else { executor.setCorePoolSize(10); executor.setMaximumPoolSize(100); executor.setKeepAliveTime(60, java.util.concurrent.TimeUnit.SECONDS); } }); } }
|
场景 3:配置 HTTPS(支持 SSL 证书)
需提前准备 SSL 证书(如通过 keytool 生成 JKS 格式证书),放置在 src/main/resources/ssl 目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Component public class TomcatSslCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory factory) { org.apache.catalina.connector.Connector sslConnector = new org.apache.catalina.connector.Connector("org.apache.coyote.http11.Http11NioProtocol"); org.apache.tomcat.util.net.SSLHostConfig sslHostConfig = new org.apache.tomcat.util.net.SSLHostConfig(); org.apache.tomcat.util.net.SSLHostConfig.Certificate cert = new org.apache.tomcat.util.net.SSLHostConfig.Certificate();
cert.setCertificateKeystoreFile("classpath:ssl/localhost-ssl.jks"); cert.setCertificateKeystorePassword("123456"); cert.setType("RSA"); sslHostConfig.addCertificate(cert); sslConnector.addSslHostConfig(sslHostConfig); sslConnector.setPort(8443);
factory.addAdditionalTomcatConnectors(sslConnector);
factory.addEngineValves(valve -> { if (valve instanceof org.apache.catalina.valves.rewrite.RewriteValve) { org.apache.catalina.valves.rewrite.RewriteValve rewriteValve = (org.apache.catalina.valves.rewrite.RewriteValve) valve; rewriteValve.setConfiguration("RewriteCond %{SERVER_PORT} ^8080$ RewriteRule ^(.*)$ https://%{SERVER_NAME}:8443$1 [R,L]"); } }); } }
|
场景 4:设置 session 超时时间
1 2 3 4 5 6 7 8 9
| @Component public class TomcatSessionCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory factory) { factory.setSessionTimeout(Duration.ofMinutes(30)); } }
|
版本迁移注意事项(1.x → 2.x+)
若需从 Spring Boot 1.x 迁移到 2.x+,定制化 Tomcat 时需注意以下兼容性调整:
- 接口替换:
EmbeddedServletContainerCustomizer → WebServerFactoryCustomizer;
- 工厂类替换:
TomcatEmbeddedServletContainerFactory → TomcatServletWebServerFactory;
- 依赖调整:确保
spring-boot-starter-web 依赖版本为 2.x+,避免混合 1.x 依赖;
- API 调整:
- session 超时:1.x 的
setSessionTimeout(int 毫秒) → 2.x+ 的 setSessionTimeout(Duration);
- 访问日志:2.x+ 新增
setAccessLogEnabled/setAccessLogPattern,替代 1.x 的 addEngineValves 手动配置;
- 泛型支持:2.x+ 建议指定
WebServerFactoryCustomizer<TomcatServletWebServerFactory> 泛型,避免强转。
总结
Spring Boot 定制内置 Tomcat 的核心逻辑跨版本一致 ——“通过定制器接口获取工厂类,再通过工厂类调整容器参数”,主要差异在于接口和工厂类的名称:
- 1.x 版本:
EmbeddedServletContainerCustomizer + TomcatEmbeddedServletContainerFactory;
- 2.x+ 版本:
WebServerFactoryCustomizer + TomcatServletWebServerFactory(推荐,API 更便捷)