内嵌 Web 服务器

每个 Spring Boot Web 应用都包含一个内嵌 Web 服务器。 这一特性引发了许多常见问题,例如如何更换内嵌服务器以及如何配置内嵌服务器。 本节将解答这些问题。

使用其他 Web 服务器

许多 Spring Boot starter 默认包含内嵌容器。

  • 对于 Servlet 栈应用,spring-boot-starter-web 通过包含 spring-boot-starter-tomcat 默认集成了 Tomcat,但你也可以选择 spring-boot-starter-jettyspring-boot-starter-undertow

  • 对于响应式栈应用,spring-boot-starter-webflux 通过包含 spring-boot-starter-reactor-netty 默认集成了 Reactor Netty,但你也可以选择 spring-boot-starter-tomcatspring-boot-starter-jettyspring-boot-starter-undertow

切换到不同的 HTTP 服务器时,你需要将默认依赖替换为所需的依赖。 为简化此过程,Spring Boot 为每个受支持的 HTTP 服务器都提供了独立的 starter。

以下 Maven 示例展示了如何排除 Tomcat 并为 Spring MVC 引入 Jetty:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<!-- 排除 Tomcat 依赖 -->
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<!-- 使用 Jetty 替代 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

以下 Gradle 示例配置了必要依赖,并通过 module replacement 机制将 Spring WebFlux 的 Reactor Netty 替换为 Undertow:

dependencies {
	implementation "org.springframework.boot:spring-boot-starter-undertow"
	implementation "org.springframework.boot:spring-boot-starter-webflux"
	modules {
		module("org.springframework.boot:spring-boot-starter-reactor-netty") {
			replacedBy("org.springframework.boot:spring-boot-starter-undertow", "使用 Undertow 替代 Reactor Netty")
		}
	}
}
spring-boot-starter-reactor-netty 是使用 WebClient 类所必需的,因此即使引入了其他 HTTP 服务器,也可能需要保留对 Netty 的依赖。

禁用 Web 服务器

如果你的 classpath 中包含启动 Web 服务器所需的组件,Spring Boot 会自动启动它。 如需禁用此行为,可在 application.properties 中配置 WebApplicationType,如下所示:

  • Properties

  • YAML

spring.main.web-application-type=none
spring:
  main:
    web-application-type: "none"

修改 HTTP 端口

在独立应用中,主 HTTP 端口默认是 8080,但可通过 server.port(例如在 application.properties 或作为系统属性)进行设置。 得益于 Environment 的松散绑定,你也可以使用 SERVER_PORT(如作为操作系统环境变量)。

如需完全关闭 HTTP 端口但仍创建 WebApplicationContext,可设置 server.port=-1(有时用于测试场景)。

更多详情参见 ‘Spring Boot Features’ 部分的 自定义内嵌 Servlet 容器,或查阅 ServerProperties 类。

使用随机未分配的 HTTP 端口

如需扫描可用端口(利用操作系统原生机制避免冲突),可设置 server.port=0

运行时获取 HTTP 端口

你可以通过日志输出或 WebServerApplicationContextWebServer 获取服务器实际运行的端口。 最可靠的方式是添加一个类型为 ApplicationListener<WebServerInitializedEvent>@Bean,在事件发布时从事件中获取容器。

使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) 的测试,也可以通过 @LocalServerPort 注解将实际端口注入到字段中,如下例所示:

  • Java

  • Kotlin

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyWebIntegrationTests {

	@LocalServerPort
	int port;

	// ...

}
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.boot.test.web.server.LocalServerPort

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyWebIntegrationTests {

	@LocalServerPort
	var port = 0

	// ...

}

@LocalServerPort@Value("${local.server.port}") 的元注解。 请勿在常规应用中尝试注入该端口。 如上所述,该值仅在容器初始化后才会被设置。 与测试不同,应用代码回调会较早执行(此时端口值尚不可用)。

启用 HTTP 响应压缩

Jetty、Tomcat、Reactor Netty 和 Undertow 均支持 HTTP 响应压缩。 可在 application.properties 中启用,如下所示:

  • Properties

  • YAML

server.compression.enabled=true
server:
  compression:
    enabled: true

默认情况下,响应内容长度需至少 2048 字节才会启用压缩。 可通过 server.compression.min-response-size 属性进行调整。

默认仅对以下内容类型的响应进行压缩:

  • text/html

  • text/xml

  • text/plain

  • text/css

  • text/javascript

  • application/javascript

  • application/json

  • application/xml

可通过 server.compression.mime-types 属性自定义此行为。

配置 SSL

可通过设置 server.ssl.* 属性(通常在 application.propertiesapplication.yaml 中)声明式配置 SSL。 详见 Ssl,了解所有支持的属性。

以下示例展示了如何使用 Java KeyStore 文件配置 SSL 属性:

  • Properties

  • YAML

server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
server.ssl.key-password=another-secret
server:
  port: 8443
  ssl:
    key-store: "classpath:keystore.jks"
    key-store-password: "secret"
    key-password: "another-secret"

采用如上配置后,应用将不再支持 8080 端口的普通 HTTP 连接。 Spring Boot 不支持通过 application.properties 同时配置 HTTP 和 HTTPS 连接器。 如需同时支持两者,需以编程方式配置其中之一。 推荐通过 application.properties 配置 HTTPS,因为 HTTP 连接器更易于编程配置。

使用 PEM 编码文件

你可以使用 PEM 编码文件替代 Java KeyStore 文件。 建议尽量使用 PKCS#8 密钥文件。 PEM 编码的 PKCS#8 密钥文件以 -----BEGIN PRIVATE KEY----------BEGIN ENCRYPTED PRIVATE KEY----- 开头。

如果你有其他格式的文件,如 PKCS#1(-----BEGIN RSA PRIVATE KEY-----)或 SEC 1(-----BEGIN EC PRIVATE KEY-----),可使用 OpenSSL 转换为 PKCS#8:

openssl pkcs8 -topk8 -nocrypt -in <input file> -out <output file>

以下示例展示了如何使用 PEM 编码的证书和私钥文件配置 SSL 属性:

  • Properties

  • YAML

server.port=8443
server.ssl.certificate=classpath:my-cert.crt
server.ssl.certificate-private-key=classpath:my-cert.key
server.ssl.trust-certificate=classpath:ca-cert.crt
server:
  port: 8443
  ssl:
    certificate: "classpath:my-cert.crt"
    certificate-private-key: "classpath:my-cert.key"
    trust-certificate: "classpath:ca-cert.crt"

使用 SSL Bundle

或者,也可以在 SSL bundle 中配置 SSL 信任材料,并按如下方式应用到 Web 服务器:

  • Properties

  • YAML

server.port=8443
server.ssl.bundle=example
server:
  port: 8443
  ssl:
    bundle: "example"

server.ssl.bundle 属性不能与 server.ssl 下的独立 Java KeyStore 或 PEM 属性选项同时使用。

使用 bundle 时,server.ssl.ciphersserver.ssl.enabled-protocolsserver.ssl.protocol 属性也会被忽略。 这些属性应通过 spring.ssl.bundle.<type>.<name>.options 属性定义。

配置 SNI(服务器名称指示)

Tomcat、Netty 和 Undertow 支持为不同主机名配置独立的 SSL 信任材料,以实现 SNI(服务器名称指示)。 Jetty 不支持 SNI 配置,但如果为其提供多个证书,Jetty 可 自动设置 SNI

假设已配置名为 webweb-alt1web-alt2SSL bundle,可按如下方式将每个 bundle 分配给内嵌 Web 服务器所服务的主机名:

  • Properties

  • YAML

server.port=8443
server.ssl.bundle=web
server.ssl.server-name-bundles[0].server-name=alt1.example.com
server.ssl.server-name-bundles[0].bundle=web-alt1
server.ssl.server-name-bundles[1].server-name=alt2.example.com
server.ssl.server-name-bundles[1].bundle=web-alt2
server:
  port: 8443
  ssl:
    bundle: "web"
    server-name-bundles:
      - server-name: "alt1.example.com"
        bundle: "web-alt1"
      - server-name: "alt2.example.com"
        bundle: "web-alt2"

server.ssl.bundle 指定的 bundle 将用于默认主机及所有支持 SNI 的客户端。 如配置了 server.ssl.server-name-bundles,则必须配置默认 bundle。

配置 HTTP/2

可通过 server.http2.enabled 配置属性在 Spring Boot 应用中启用 HTTP/2 支持。 同时支持 h2(基于 TLS 的 HTTP/2)和 h2c(基于 TCP 的 HTTP/2)。 如需使用 h2,还需启用 SSL。 未启用 SSL 时,将使用 h2c。 例如,当你的应用 部署在执行 TLS 终止的代理服务器后 时,可能希望使用 h2c

Tomcat 的 HTTP/2

Spring Boot 默认集成 Tomcat 10.1.x,原生支持 h2ch2。 另外,如果主机操作系统已安装 libtcnative 及其依赖库,也可通过该库支持 h2

如未将库目录加入 JVM 库路径,需要通过 JVM 参数(如 -Djava.library.path=/usr/local/opt/tomcat-native/lib)指定。 更多信息请参见 官方 Tomcat 文档

Jetty 的 HTTP/2

Jetty 支持 HTTP/2 需额外引入 org.eclipse.jetty.http2:jetty-http2-server 依赖。 如仅需 h2c,无需其他依赖。 如需 h2,还需根据部署环境选择以下依赖之一:

  • 使用 JDK 内置支持时引入 org.eclipse.jetty:jetty-alpn-java-server

  • 或引入 org.eclipse.jetty:jetty-alpn-conscrypt-serverConscrypt 库

Reactor Netty 的 HTTP/2

spring-boot-webflux-starter 默认使用 Reactor Netty 作为服务器。 Reactor Netty 原生支持 h2ch2。 为获得最佳运行时性能,还支持通过本地库实现 h2。 如需启用本地库,需额外引入依赖。

Spring Boot 管理 io.netty:netty-tcnative-boringssl-static “uber jar” 版本,该 jar 包含所有平台的本地库。 开发者也可按需通过 classifier 仅引入所需依赖(详见 Netty 官方文档)。

Undertow 的 HTTP/2

Undertow 原生支持 h2ch2

配置 Web 服务器

通常建议优先使用丰富的配置项,通过在 application.propertiesapplication.yaml 文件中添加新条目自定义 Web 服务器。 参见 发现外部属性的内置选项server.* 命名空间非常实用,包括 server.tomcat.*server.jetty.* 等服务器专属命名空间。 完整列表见 常用应用属性

前文已涵盖压缩、SSL、HTTP/2 等常见场景。 如无现成配置项满足需求,可考虑实现 WebServerFactoryCustomizer。 你可以声明该组件并获取所选服务器工厂(Tomcat、Jetty、Reactor Netty、Undertow)及所选 Web 栈(servlet 或 reactive)的访问权。

下例为基于 spring-boot-starter-web(servlet 栈)的 Tomcat 配置:

  • Java

  • Kotlin

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;

@Component
public class MyTomcatWebServerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

	@Override
	public void customize(TomcatServletWebServerFactory factory) {
		// customize the factory here
	}

}
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory
import org.springframework.boot.web.server.WebServerFactoryCustomizer
import org.springframework.stereotype.Component

@Component
class MyTomcatWebServerCustomizer : WebServerFactoryCustomizer<TomcatServletWebServerFactory?> {

	override fun customize(factory: TomcatServletWebServerFactory?) {
		// customize the factory here
	}

}
Spring Boot 内部正是通过该机制实现服务器自动配置。 自动配置的 WebServerFactoryCustomizer bean 顺序为 0,会在用户自定义定制器之前处理,除非用户显式指定顺序。

通过自定义器获取 WebServerFactory 后,可用其配置连接器、服务器资源或服务器本身,均通过服务器专属 API 实现。

此外,Spring Boot 还提供:

服务器 Servlet 栈 Reactive 栈

Tomcat

TomcatServletWebServerFactory

TomcatReactiveWebServerFactory

Jetty

JettyServletWebServerFactory

JettyReactiveWebServerFactory

Undertow

UndertowServletWebServerFactory

UndertowReactiveWebServerFactory

Reactor

N/A

NettyReactiveWebServerFactory

如无更优方案,也可声明自定义 WebServerFactory bean,将覆盖 Spring Boot 提供的默认工厂。 此时自动配置的定制器依然会应用于你的自定义工厂,请谨慎使用。

向应用添加 Servlet、Filter 或 Listener

在基于 spring-boot-starter-web 的 servlet 栈应用中,有两种方式向应用添加 ServletFilterServletContextListener 及 Servlet API 支持的其他监听器:

通过 Spring Bean 添加 Servlet、Filter 或 Listener

如需通过 Spring bean 添加 ServletFilter 或 servlet *Listener,需为其提供 @Bean 定义。 这种方式便于注入配置或依赖。 但需注意避免导致过多其他 bean 的提前初始化,因为这些组件需在应用生命周期早期安装到容器中。 (例如,不建议依赖 DataSource 或 JPA 配置。) 可通过首次使用时延迟初始化 bean 规避此限制。

对于 filter 和 servlet,还可通过添加 FilterRegistrationBeanServletRegistrationBean,为底层组件补充映射和初始化参数。 也可使用 @ServletRegistration@FilterRegistration 注解,作为 ServletRegistrationBeanFilterRegistrationBean 的注解替代方案。

如未在 filter 注册时指定 dispatcherType,则默认为 REQUEST,与 servlet 规范一致。

与其他 Spring bean 一样,你可以定义 servlet filter bean 的顺序,详见 将 Servlets、Filters 和 Listeners 注册为 Spring Beans

禁用 Servlet 或 Filter 的注册

如前文 所述,任何 ServletFilter bean 都会自动注册到 servlet 容器。 如需禁用某个 FilterServlet bean 的注册,可为其创建注册 bean 并标记为禁用,示例如下:

  • Java

  • Kotlin

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyFilterConfiguration {

	@Bean
	public FilterRegistrationBean<MyFilter> registration(MyFilter filter) {
		FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(filter);
		registration.setEnabled(false);
		return registration;
	}

}
import org.springframework.boot.web.servlet.FilterRegistrationBean
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyFilterConfiguration {

	@Bean
	fun registration(filter: MyFilter): FilterRegistrationBean<MyFilter> {
		val registration = FilterRegistrationBean(filter)
		registration.isEnabled = false
		return registration
	}

}

通过类路径扫描添加 Servlet、Filter 和 Listener

@WebServlet@WebFilter@WebListener 注解的类,可通过在 @Configuration 类上添加 @ServletComponentScan 注解并指定待注册组件所在包,实现自动注册到内嵌 servlet 容器。 默认情况下,@ServletComponentScan 从注解类所在包开始扫描。

配置访问日志

Tomcat、Undertow 和 Jetty 均可通过各自命名空间配置访问日志。

例如,以下设置可在 Tomcat 上按 自定义模式记录访问日志:

  • Properties

  • YAML

server.tomcat.basedir=my-tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a %r %s (%D microseconds)
server:
  tomcat:
    basedir: "my-tomcat"
    accesslog:
      enabled: true
      pattern: "%t %a %r %s (%D microseconds)"
日志默认存放于 Tomcat 基目录下的 logs 目录。 默认情况下,logs 目录为临时目录,因此建议固定 Tomcat 基目录或为日志指定绝对路径。 上述示例中,日志位于应用工作目录下的 my-tomcat/logs

Undertow 的访问日志配置方式类似,示例如下:

  • Properties

  • YAML

server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=%t %a %r %s (%D milliseconds)
server.undertow.options.server.record-request-start-time=true
server:
  undertow:
    accesslog:
      enabled: true
      pattern: "%t %a %r %s (%D milliseconds)"
    options:
      server:
        record-request-start-time: true

注意,除了启用访问日志和配置日志模式外,还启用了请求开始时间记录。 如需在访问日志模式中包含响应时间(%D),必须启用该选项。 日志存放于应用工作目录下的 logs 目录。 可通过 server.undertow.accesslog.dir 属性自定义日志目录。

Jetty 的访问日志配置如下:

  • Properties

  • YAML

server.jetty.accesslog.enabled=true
server.jetty.accesslog.filename=/var/log/jetty-access.log
server:
  jetty:
    accesslog:
      enabled: true
      filename: "/var/log/jetty-access.log"

默认情况下,日志重定向至 System.err。 更多详情请参见 Jetty 文档。

运行于前端代理服务器之后

如果你的应用部署在代理、负载均衡器或云环境中,请求信息(如主机、端口、协议等)可能会在传递过程中发生变化。 你的应用实际运行在 10.10.10.10:8080,但 HTTP 客户端应只看到 example.org

RFC7239 "Forwarded Headers" 定义了 Forwarded HTTP 头,代理可用该头传递原始请求信息。 你可以配置应用读取这些头部,并在生成链接、HTTP 302 跳转、JSON 文档或 HTML 页面时自动使用这些信息。 此外还有一些非标准头部,如 X-Forwarded-HostX-Forwarded-PortX-Forwarded-ProtoX-Forwarded-SslX-Forwarded-Prefix

如果代理添加了常用的 X-Forwarded-ForX-Forwarded-Proto 头,只需将 server.forward-headers-strategy 设置为 NATIVE 即可支持。 此选项下,Web 服务器自身原生支持该特性,具体行为可查阅各自文档。

如仍无法满足需求,Spring Framework 为 servlet 栈提供了 ForwardedHeaderFilter,为 reactive 栈提供了 ForwardedHeaderTransformer。 可通过将 server.forward-headers-strategy 设为 FRAMEWORK 启用。

若使用 Tomcat 并在代理处终止 SSL,应将 server.tomcat.redirect-context-root 设为 false,以便在重定向前优先处理 X-Forwarded-Proto 头。
若应用运行在 受支持的云平台server.forward-headers-strategy 属性默认值为 NATIVE,其他情况默认为 NONE

定制 Tomcat 的代理配置

如使用 Tomcat,可进一步配置用于传递“forwarded”信息的头部名称,示例如下:

  • Properties

  • YAML

server.tomcat.remoteip.remote-ip-header=x-your-remote-ip-header
server.tomcat.remoteip.protocol-header=x-your-protocol-header
server:
  tomcat:
    remoteip:
      remote-ip-header: "x-your-remote-ip-header"
      protocol-header: "x-your-protocol-header"

Tomcat 还配置了用于匹配受信任内部代理的正则表达式。 默认值见 server.tomcat.remoteip.internal-proxies 附录。 可通过在 application.properties 添加如下配置自定义该阀门:

  • Properties

  • YAML

server.tomcat.remoteip.internal-proxies=192\.168\.\d{1,3}\.\d{1,3}
server:
  tomcat:
    remoteip:
      internal-proxies: "192\\.168\\.\\d{1,3}\\.\\d{1,3}"
若将 internal-proxies 设为空则信任所有代理(生产环境请勿如此配置)。

如需完全控制 Tomcat 的 RemoteIpValve 配置,可关闭自动配置(即设置 server.forward-headers-strategy=NONE),并通过 WebServerFactoryCustomizer bean 添加新阀门实例。

启用 Tomcat 多连接器

可向 TomcatServletWebServerFactory 添加 Connector,以支持多个连接器(如 HTTP 和 HTTPS),示例如下:

  • Java

  • Kotlin

import org.apache.catalina.connector.Connector;

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyTomcatConfiguration {

	@Bean
	public WebServerFactoryCustomizer<TomcatServletWebServerFactory> connectorCustomizer() {
		return (tomcat) -> tomcat.addAdditionalTomcatConnectors(createConnector());
	}

	private Connector createConnector() {
		Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
		connector.setPort(8081);
		return connector;
	}

}
import org.apache.catalina.connector.Connector
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory
import org.springframework.boot.web.server.WebServerFactoryCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyTomcatConfiguration {

	@Bean
	fun connectorCustomizer(): WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
		return WebServerFactoryCustomizer { tomcat: TomcatServletWebServerFactory ->
			tomcat.addAdditionalTomcatConnectors(
				createConnector()
			)
		}
	}

	private fun createConnector(): Connector {
		val connector = Connector("org.apache.coyote.http11.Http11NioProtocol")
		connector.port = 8081
		return connector
	}

}

启用 Tomcat 的 MBean 注册表

内嵌 Tomcat 默认禁用 MBean 注册表,以降低内存占用。 如需使用 Tomcat 的 MBean(如通过 Micrometer 暴露指标),可通过 server.tomcat.mbeanregistry.enabled 属性启用,示例如下:

  • Properties

  • YAML

server.tomcat.mbeanregistry.enabled=true
server:
  tomcat:
    mbeanregistry:
      enabled: true

启用 Undertow 多监听器

UndertowServletWebServerFactory 添加 UndertowBuilderCustomizer,并在 io.undertow.Undertow.Builder 上添加监听器,示例如下:

  • Java

  • Kotlin

import io.undertow.Undertow.Builder;

import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyUndertowConfiguration {

	@Bean
	public WebServerFactoryCustomizer<UndertowServletWebServerFactory> undertowListenerCustomizer() {
		return (factory) -> factory.addBuilderCustomizers(this::addHttpListener);
	}

	private Builder addHttpListener(Builder builder) {
		return builder.addHttpListener(8080, "0.0.0.0");
	}

}
import io.undertow.Undertow
import org.springframework.boot.web.embedded.undertow.UndertowBuilderCustomizer
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory
import org.springframework.boot.web.server.WebServerFactoryCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyUndertowConfiguration {

	@Bean
	fun undertowListenerCustomizer(): WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
		return WebServerFactoryCustomizer { factory: UndertowServletWebServerFactory ->
			factory.addBuilderCustomizers(
				UndertowBuilderCustomizer { builder: Undertow.Builder -> addHttpListener(builder) })
		}
	}

	private fun addHttpListener(builder: Undertow.Builder): Undertow.Builder {
		return builder.addHttpListener(8080, "0.0.0.0")
	}

}

使用 @ServerEndpoint 创建 WebSocket 端点

如需在使用内嵌容器的 Spring Boot 应用中使用 @ServerEndpoint,需声明一个 ServerEndpointExporter @Bean,示例如下:

  • Java

  • Kotlin

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration(proxyBeanMethods = false)
public class MyWebSocketConfiguration {

	@Bean
	public ServerEndpointExporter serverEndpointExporter() {
		return new ServerEndpointExporter();
	}

}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.socket.server.standard.ServerEndpointExporter

@Configuration(proxyBeanMethods = false)
class MyWebSocketConfiguration {

	@Bean
	fun serverEndpointExporter(): ServerEndpointExporter {
		return ServerEndpointExporter()
	}

}

上述 bean 会将所有 @ServerEndpoint 注解的 bean 注册到底层 WebSocket 容器。 如部署到独立 servlet 容器,则由 servlet 容器初始化器完成该角色,无需 ServerEndpointExporter bean。