嵌入式 Web 服务器

每个 Spring Boot Web 应用程序都包含一个嵌入式 Web 服务器。此功能导致了许多操作指南问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器。本节将解答这些问题。

使用其他 Web 服务器

许多 Spring Boot 启动器包含默认的嵌入式容器。

  • 对于 Servlet 栈应用程序,spring-boot-starter-web 通过包含 spring-boot-starter-tomcat 来包含 Tomcat,但您可以改为使用 spring-boot-starter-jettyspring-boot-starter-undertow

  • 对于 Reactive 栈应用程序,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 服务器提供了一个单独的启动器。

以下 Maven 示例演示了如何排除 Tomcat 并为 Spring MVC 包含 Jetty

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<!-- Exclude the Tomcat dependency -->
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

以下 Gradle 示例配置了必要的依赖项和一个模块替换,以便在 Spring WebFlux 中使用 Undertow 代替 Reactor Netty

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", "Use Undertow instead of Reactor Netty")
		}
	}
}
spring-boot-starter-reactor-netty 是使用 WebClient 类所必需的,因此即使您需要包含不同的 HTTP 服务器,也可能需要保留对 Netty 的依赖项。

禁用 Web 服务器

如果您的类路径包含启动 Web 服务器的必要内容,Spring Boot 将自动启动它。要禁用此行为,请在您的 application.properties 中配置 WebApplicationType,如下例所示

  • 属性

  • 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 功能”部分中的自定义嵌入式 Servlet 容器,或ServerProperties 类。

使用随机未分配的 HTTP 端口

要扫描空闲端口(使用操作系统原生方法来防止冲突),请使用 server.port=0

在运行时发现 HTTP 端口

您可以从日志输出或通过其 WebServerWebServerApplicationContext 访问服务器正在运行的端口。获取该端口并确保它已初始化的最佳方法是添加类型为 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 响应压缩

HTTP 响应压缩受 Jetty、Tomcat、Reactor Netty 和 Undertow 支持。它可以在 application.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.* 属性来声明性地配置 SSL,通常在 application.propertiesapplication.yaml 中。有关所有受支持属性的详细信息,请参阅Ssl

以下示例演示了如何使用 Java 密钥库文件设置 SSL 属性

  • 属性

  • 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 密钥库文件。您应尽可能使用 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 属性

  • 属性

  • 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 捆绑包

或者,可以在SSL 捆绑包中配置 SSL 信任材料,并将其应用于 Web 服务器,如本例所示

  • 属性

  • YAML

server.port=8443
server.ssl.bundle=example
server:
  port: 8443
  ssl:
    bundle: "example"
server.ssl.bundle 属性不能与 server.ssl 下的离散 Java 密钥库或 PEM 属性选项组合使用。

配置服务器名称指示

Tomcat、Netty 和 Undertow 可以配置为对单个主机名使用唯一的 SSL 信任材料以支持服务器名称指示 (SNI)。Jetty 不支持 SNI 配置,但如果向其提供了多个证书,Jetty 可以自动设置 SNI

假设已配置名为 webweb-alt1web-alt2SSL 捆绑包,则可以使用以下配置将每个捆绑包分配给嵌入式 Web 服务器服务的主机名

  • 属性

  • 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 指定的捆绑包将用于默认主机,以及任何不支持 SNI 的客户端。如果配置了任何 server.ssl.server-name-bundles,则必须配置此默认捆绑包。

配置 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

对于 HTTP/2 支持,Jetty 需要额外的 org.eclipse.jetty.http2:jetty-http2-server 依赖项。要使用 h2c,不需要其他依赖项。要使用 h2,您还需要根据您的部署选择以下依赖项之一

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

  • 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” 的版本,其中包含所有平台的原生库。开发人员可以选择仅使用分类器导入所需的依赖项(请参阅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 提供的 Bean。当你这样做时,自动配置的自定义程序仍然会应用于你的自定义工厂,因此请谨慎使用此选项。

向应用程序添加 Servlet、过滤器或监听器

在 servlet 栈应用程序中,即使用spring-boot-starter-web,有两种方法可以向应用程序添加ServletFilterServletContextListener以及 Servlet API 支持的其他监听器。

使用 Spring Bean 添加 Servlet、过滤器或监听器

要使用 Spring Bean 添加ServletFilter或 servlet *Listener,必须为此提供@Bean定义。当你想要注入配置或依赖项时,这样做非常有用。但是,你必须非常小心,不要导致过多其他 Bean 的急切初始化,因为它们必须在应用程序生命周期的早期安装到容器中。(例如,让它们依赖于你的DataSource或 JPA 配置不是一个好主意。)可以通过在首次使用时延迟初始化 Bean 而不是在初始化时来解决此类限制。

在过滤器和 servlet 的情况下,你还可以通过添加FilterRegistrationBeanServletRegistrationBean来添加映射和初始化参数,而不是或除了底层组件之外。

如果在过滤器注册上未指定dispatcherType,则使用REQUEST。这与 servlet 规范的默认调度程序类型一致。

像任何其他 Spring Bean 一样,你可以定义 servlet 过滤器 Bean 的顺序;请务必查看将 Servlet、过滤器和监听器注册为 Spring Bean部分。

禁用 Servlet 或过滤器的注册

前面所述,任何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、过滤器和监听器

通过使用@ServletComponentScan注解@Configuration类并指定包含要注册的组件的包,可以将使用@WebServlet@WebFilter@WebListener注解的类自动注册到嵌入式 servlet 容器中。默认情况下,@ServletComponentScan会从带注解类的包中进行扫描。

配置访问日志

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

例如,以下设置使用自定义模式在 Tomcat 上记录访问。

  • 属性

  • 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 的访问日志,如下例所示

  • 属性

  • 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 的访问日志

  • 属性

  • 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 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,还可以配置用于承载“转发”信息的标头的名称,如下例所示

  • 属性

  • 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添加条目来自定义阀门的配置,如下例所示

  • 属性

  • 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 的RemoteIpValve的配置。

使用 Tomcat 启用多个连接器

可以将org.apache.catalina.connector.Connector添加到TomcatServletWebServerFactory中,这可以允许多个连接器,包括 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 的内存占用。如果你想使用 Tomcat 的 MBean,例如使它们可以被 Micrometer 用于公开指标,则必须使用server.tomcat.mbeanregistry.enabled属性来执行此操作,如下例所示

  • 属性

  • YAML

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

使用 Undertow 启用多个监听器

UndertowBuilderCustomizer添加到UndertowServletWebServerFactory并向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。