1. 概述

Spring Boot 2 发布后,不少老项目在升级时都会遇到一个常见问题:编译报错找不到 EmbeddedServletContainerCustomizerConfigurableEmbeddedServletContainer

✅ 这两个类确实被移除了,但别慌——功能不仅没丢,还更清晰了。
❌ 直接搜“类不存在”然后瞎改,很容易踩坑。

取而代之的是:

  • WebServerFactoryCustomizer 接口(替代 EmbeddedServletContainerCustomizer
  • ConfigurableServletWebServerFactory 类(替代 ConfigurableEmbeddedServletContainer

本文带你平滑过渡,快速完成升级。


2. Spring Boot 2 之前的写法

在 Spring Boot 1.x 中,自定义内嵌 Web 容器(如 Tomcat)的常见方式是实现 EmbeddedServletContainerCustomizer 接口。

基础配置示例

@Component
public class CustomContainer implements EmbeddedServletContainerCustomizer {
 
    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
        container.setPort(8080);
        container.setContextPath("");
     }
}

这段代码干了两件事:

  • 将服务端口改为 8080
  • 将上下文路径(context path)设为空,即应用根路径为 /

针对特定容器的定制(如 Tomcat)

如果需要调用 Tomcat 特有的 API,会做类型判断:

@Component
public class CustomContainer implements EmbeddedServletContainerCustomizer {
 
    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
        if (container instanceof TomcatEmbeddedServletContainerFactory) {
            TomcatEmbeddedServletContainerFactory tomcatContainer = 
              (TomcatEmbeddedServletContainerFactory) container;
            tomcatContainer.setPort(8080);
            tomcatContainer.setContextPath("");
        }
    }
}

⚠️ 这种写法在 Spring Boot 2 中直接编译失败,因为相关类已被移除。


3. 升级到 Spring Boot 2 的正确姿势

Spring Boot 2 统一了 Web 容器的抽象模型,引入了新的命名规范:

旧类/接口(Spring Boot 1.x) 新类/接口(Spring Boot 2+)
EmbeddedServletContainerCustomizer WebServerFactoryCustomizer
ConfigurableEmbeddedServletContainer ConfigurableServletWebServerFactory
TomcatEmbeddedServletContainerFactory TomcatServletWebServerFactory
JettyEmbeddedServletContainerFactory JettyServletWebServerFactory
UndertowEmbeddedServletContainerFactory UndertowServletWebServerFactory

通用配置写法(推荐)

适用于所有 Servlet 容器的通用定制:

@Component
public class CustomContainer implements 
  WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
 
    @Override
    public void customize(ConfigurableServletWebServerFactory factory) {
        factory.setPort(8080);
        factory.setContextPath("");
     }
}

✅ 简单粗暴,无需关心底层是 Tomcat 还是 Undertow,只要它是 Servlet 容器就能生效。

针对 Tomcat 的定制

若需调用 Tomcat 特有方法(比如连接器配置、线程池等),应使用具体工厂类型作为泛型:

@Component
public class CustomContainer implements 
  WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        factory.setContextPath("");
        factory.setPort(8080);
        // 此处还可调用 Tomcat 专属方法,如:
        // factory.addConnectorCustomizers(connector -> { ... });
    }
}

📌 提示:TomcatServletWebServerFactory 提供了更多 Tomcat 特有的扩展点,比如添加连接器定制器、设置 SSL、启用 HTTP2 等。

其他容器同理:

  • Jetty → JettyServletWebServerFactory
  • Undertow → UndertowServletWebServerFactory

只要按新命名规则替换即可,API 设计保持一致。


4. 总结

Spring Boot 2 的这次重构并非功能删除,而是接口规范化的结果。

关键点回顾:

✅ 使用 WebServerFactoryCustomizer<T> 替代旧的 EmbeddedServletContainerCustomizer
✅ 泛型参数选择合适的 *ServletWebServerFactory 实现
✅ 通用需求用 ConfigurableServletWebServerFactory,特定容器用具体工厂类
✅ 所有配置仍通过 @Component 注入 Spring 容器生效

示例代码已整理至 GitHub:https://github.com/spring-tutorials/spring-boot-web-customization

升级不难,关键是理解背后的抽象模型变化。掌握这套新机制后,后续扩展容器行为(比如自定义错误页、SSL 配置、访问日志等)也会更加得心应手。


原始标题:Container Configuration in Spring Boot 2

« 上一篇: Java Weekly, 第238期