嵌入式 Web 服务器

每个 Spring Boot Web 应用程序都包含一个内嵌的 Web 服务器。 这一特性引发了许多“如何做”的问题,包括如何更换内嵌服务器以及如何配置内嵌服务器。 本节将回答这些问题。spring-doc.cadn.net.cn

使用其他 Web 服务器

许多 Spring Boot Starter 包含默认的嵌入式容器。spring-doc.cadn.net.cn

  • 对于 Servlet 栈应用程序,spring-boot-starter-web 通过包含 spring-boot-starter-tomcat 来引入 Tomcat,但你也可以改用 spring-boot-starter-jettyspring-doc.cadn.net.cn

  • 对于响应式栈应用程序,spring-boot-starter-webflux 通过包含 spring-boot-starter-reactor-netty 来引入 Reactor Netty,但你也可以改用 spring-boot-starter-tomcatspring-boot-starter-jettyspring-doc.cadn.net.cn

切换到不同的 HTTP 服务器时,您需要将默认依赖项替换为您所需的依赖项。 为协助完成此过程,Spring Boot 为每个受支持的 HTTP 服务器都提供了单独的 starter。spring-doc.cadn.net.cn

以下示例展示了如何排除 Tomcat 并为 Spring MVC 引入 Jetty:spring-doc.cadn.net.cn

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-webmvc</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>
dependencies {
	implementation('org.springframework.boot:spring-boot-starter-webmvc') {
		// Exclude the Tomcat dependency
		exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
	}
	// Use Jetty instead
	implementation "org.springframework.boot:spring-boot-starter-jetty"
}

如果你正在创建一个 WAR 文件,可以使用类似的方法,但必须指明 provided 依赖项:spring-doc.cadn.net.cn

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-webmvc</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>
	<scope>provided</scope>
</dependency>
dependencies {
	implementation('org.springframework.boot:spring-boot-starter-webmvc') {
		// Exclude the Tomcat dependency
		exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
	}
	// Use Jetty instead
	implementation "org.springframework.boot:spring-boot-starter-jetty"
	providedRuntime "org.springframework.boot:spring-boot-starter-jetty-runtime"
}

禁用 Web 服务器

如果您的类路径包含启动 Web 服务器所需的必要组件,Spring Boot 将自动启动它。 要禁用此行为,请在您的 application.properties 中配置 WebApplicationType,如下例所示:spring-doc.cadn.net.cn

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

更改 HTTP 端口

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

若要完全关闭 HTTP 端点但仍创建 WebApplicationContext,请使用 server.port=-1(这样做有时对测试很有用)。spring-doc.cadn.net.cn

更多详情,请参阅‘Spring Boot 特性’部分中的 自定义嵌入式 Servlet 容器,或 ServerProperties 类。spring-doc.cadn.net.cn

使用随机未分配的 HTTP 端口

要扫描一个空闲端口(使用操作系统原生机制以避免冲突),请使用 server.port=0spring-doc.cadn.net.cn

在运行时发现 HTTP 端口

您可以从日志输出中,或通过 WebServerApplicationContextWebServer 访问服务器运行的端口。 获取该端口并确保其已初始化的最佳方法是添加一个类型为 ApplicationListener<WebServerInitializedEvent>@Bean,并在事件发布时从中提取容器。spring-doc.cadn.net.cn

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

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}") 的元注解。 请勿在常规应用程序中尝试注入端口。 正如我们刚才所见,该值仅在容器初始化后才会被设置。 与测试相反,应用程序代码回调会在早期处理(在实际值可用之前)。spring-doc.cadn.net.cn

针对测试 Web 服务器构建 URI

启动 WebServer(例如 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT))的测试可以使用 LocalTestWebServer 获取有关运行中服务器的信息,如下例所示:spring-doc.cadn.net.cn

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.context.ApplicationContext;

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

	@Autowired
	ApplicationContext context;

	// ...

	@Test
	void test() {
		String urlToTest = LocalTestWebServer.obtain(this.context).uri("/test");
	}

}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.boot.test.http.server.LocalTestWebServer
import org.springframework.context.ApplicationContext

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyWebIntegrationTests(@Autowired val context: ApplicationContext) {

	// ...

	@Test
	fun test() {
		val urlToTest = LocalTestWebServer.obtain(this.context).uri("/test")
	}

}

LocalTestWebServer 提供对合适的 UriBuilderFactory 的访问。 它还可以进行自定义,以便在应用程序的子路径上构建此类实例。spring-doc.cadn.net.cn

启用 HTTP 响应压缩

HTTP 响应压缩由 Jetty、Tomcat 和 Reactor Netty 支持。 可以在 application.properties 中启用,如下所示:spring-doc.cadn.net.cn

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

默认情况下,响应内容长度必须至少为 2048 字节才会执行压缩。 你可以通过设置 server.compression.min-response-size 属性来配置此行为。spring-doc.cadn.net.cn

默认情况下,仅当响应的内容类型属于以下类型之一时,才会对其进行压缩:spring-doc.cadn.net.cn

您可以通过设置 server.compression.mime-types 属性来配置此行为。spring-doc.cadn.net.cn

配置 SSL

SSL 可以通过设置各种 server.ssl.* 属性以声明方式进行配置,通常是在 application.propertiesapplication.yaml 中。 请参阅 Ssl 了解所有支持属性的详细信息。spring-doc.cadn.net.cn

以下示例展示了如何使用 Java KeyStore 文件设置 SSL 属性:spring-doc.cadn.net.cn

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 连接器更容易通过编程方式进行配置。spring-doc.cadn.net.cn

使用 PEM 编码文件

您可以使用 PEM 编码的文件来代替 Java KeyStore 文件。 应尽可能使用 PKCS#8 密钥文件。 PEM 编码的 PKCS#8 密钥文件以 -----BEGIN PRIVATE KEY----------BEGIN ENCRYPTED PRIVATE KEY----- 标头开头。spring-doc.cadn.net.cn

如果你有其他格式的文件,例如 PKCS#1(-----BEGIN RSA PRIVATE KEY-----)或 SEC 1(-----BEGIN EC PRIVATE KEY-----),你可以使用 OpenSSL 将它们转换为 PKCS#8 格式:spring-doc.cadn.net.cn

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

以下示例展示了如何使用 PEM 编码的证书和私钥文件来设置 SSL 属性:spring-doc.cadn.net.cn

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 服务器:spring-doc.cadn.net.cn

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

server.ssl.bundle 属性不能与 server.ssl 下的独立 Java KeyStore 或 PEM 属性选项结合使用。spring-doc.cadn.net.cn

当使用 SSL 套件(bundle)时,server.ssl.ciphersserver.ssl.enabled-protocolsserver.ssl.protocol 属性也会被忽略。 应改用 spring.ssl.bundle.<type>.<name>.options 属性来定义这些配置。spring-doc.cadn.net.cn

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

Tomcat 和 Netty 可以配置为针对各个主机名使用独立的 SSL 信任材料,以支持服务器名称指示(SNI)。 Jetty 不支持 SNI 配置,但如果向 Jetty 提供多个证书,它可以自动设置 SNIspring-doc.cadn.net.cn

假设已配置了名为 xref page../reference/features/ssl.htmlwebSSL 证书包,则可以使用以下配置将每个证书包分配给嵌入式 Web 服务器所服务的主机名:spring-doc.cadn.net.cn

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,则必须配置此默认证书包。spring-doc.cadn.net.cn

配置 HTTP/2

您可以通过 server.http2.enabled 配置属性在 Spring Boot 应用程序中启用 HTTP/2 支持。 同时支持 h2(基于 TLS 的 HTTP/2)和 h2c(基于 TCP 的 HTTP/2)。 要使用 h2,还必须启用 SSL。 当未启用 SSL 时,将使用 h2c。 例如,当您的应用程序运行在执行 TLS 终止的代理服务器之后时,您可能希望使用 #howto.webserver.use-behind-a-proxy-serverspring-doc.cadn.net.cn

使用 Tomcat 的 HTTP/2

Spring Boot 默认自带 Tomcat 11.0.x,该版本开箱即支持 h2ch2。 或者,如果主机操作系统上已安装 libtcnative 库及其依赖项,你也可以使用它来支持 h2spring-doc.cadn.net.cn

必须将库目录添加到 JVM 库路径中(如果尚未添加)。 您可以通过 JVM 参数来实现,例如 -Djava.library.path=/usr/local/opt/tomcat-native/lib。 更多详情请参阅官方 Tomcat 文档spring-doc.cadn.net.cn

使用 Jetty 的 HTTP/2

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

使用 Reactor Netty 的 HTTP/2

spring-boot-webflux-starter 默认使用 Reactor Netty 作为服务器。 Reactor Netty 开箱即支持 h2ch2。 为了获得最佳的运行时性能,该服务器还通过原生库支持 h2。 要启用此功能,您的应用程序需要添加一个额外的依赖项。spring-doc.cadn.net.cn

Spring Boot 管理 io.netty:netty-tcnative-boringssl-static 这个“全能 JAR”(uber jar)的版本,该 JAR 包含了所有平台的原生库。 开发者可以选择使用分类器(classifier)仅导入所需的依赖项(参见Netty 官方文档)。spring-doc.cadn.net.cn

配置 Web 服务器

通常,您应首先考虑使用众多可用的配置键之一,并通过在 application.propertiesapplication.yaml 文件中添加新条目来自定义您的 Web 服务器。 请参阅 探索外部属性的内置选项)。 server.* 命名空间在此非常有用,它包含了如 server.tomcat.*server.jetty.* 等用于服务器特定功能的命名空间。 请参阅 常用应用程序属性 列表。spring-doc.cadn.net.cn

前面的章节已经涵盖了许多常见用例,例如压缩、SSL 或 HTTP/2。 然而,如果您的用例没有对应的配置键,则应查看 WebServerFactoryCustomizer。 您可以声明此类组件并访问与您选择相关的服务器工厂:您应为所选的服务器(Tomcat、Jetty、Reactor Netty)和所选的 Web 栈(Servlet 或响应式)选择相应的变体。spring-doc.cadn.net.cn

以下示例适用于使用 spring-boot-starter-web(Servlet 栈)的 Tomcat:spring-doc.cadn.net.cn

import org.springframework.boot.tomcat.servlet.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.tomcat.servlet.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-doc.cadn.net.cn

此外,Spring Boot 还提供了:spring-doc.cadn.net.cn

服务器 Servlet 栈 响应式栈

Tomcatspring-doc.cadn.net.cn

TomcatServletWebServerFactoryspring-doc.cadn.net.cn

TomcatReactiveWebServerFactoryspring-doc.cadn.net.cn

Jettyspring-doc.cadn.net.cn

JettyServletWebServerFactoryspring-doc.cadn.net.cn

JettyReactiveWebServerFactoryspring-doc.cadn.net.cn

Reactorspring-doc.cadn.net.cn

N/Aspring-doc.cadn.net.cn

NettyReactiveWebServerFactoryspring-doc.cadn.net.cn

作为最后的手段,您还可以声明自己的 WebServerFactory Bean,它将覆盖 Spring Boot 提供的 Bean。 当您这样做时,自动配置的定制器仍会应用于您的自定义工厂,因此请谨慎使用此选项。spring-doc.cadn.net.cn

向应用程序添加 Servlet、Filter 或 Listener

在 Servlet 栈应用程序中,即使用 spring-boot-starter-web 时,有两种方式可以向您的应用程序添加 ServletFilterServletContextListener 以及 Servlet API 支持的其他监听器:spring-doc.cadn.net.cn

通过使用 Spring Bean 添加 Servlet、Filter 或 Listener

要通过使用 Spring Bean 添加 ServletFilter 或 Servlet *Listener,您必须为其提供 @Bean 定义。 当您想要注入配置或依赖项时,这样做非常有用。 然而,您必须非常小心,确保它们不会导致过多其他 Bean 的急切初始化,因为它们必须在应用程序生命周期的非常早期阶段安装到容器中。 (例如,让它们依赖于您的 DataSource 或 JPA 配置并不是一个好主意。) 您可以通过在首次使用时惰性初始化这些 Bean,而不是在初始化时立即初始化,来规避此类限制。spring-doc.cadn.net.cn

对于过滤器和 Servlet,您还可以通过添加 FilterRegistrationBeanServletRegistrationBean 来注册映射和初始化参数,以替代底层组件或作为其补充。 您也可以使用 @ServletRegistration@FilterRegistration 作为 ServletRegistrationBeanFilterRegistrationBean 的基于注解的替代方案。spring-doc.cadn.net.cn

如果在过滤器注册中未指定 dispatcherType,则使用 REQUEST。 这与 Servlet 规范的默认分发器类型一致。spring-doc.cadn.net.cn

与其他任何 Spring Bean 一样,您可以定义 Servlet 过滤器 Bean 的顺序;请务必查看将 Servlet、过滤器和监听器注册为 Spring Bean一节。spring-doc.cadn.net.cn

禁用 Servlet 或 Filter 的注册

正如前文所述,任何ServletFilter Bean 都会自动注册到 Servlet 容器中。 若要禁用特定FilterServlet Bean 的注册,请为其创建一个注册 Bean 并将其标记为已禁用,如下例所示:spring-doc.cadn.net.cn

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、过滤器和监听器

@WebServlet@WebFilter@WebListener 注解的类可以通过使用 @ServletComponentScan 注解一个 @Configuration 类,并指定包含要注册组件的包,从而自动注册到嵌入式 Servlet 容器中。 默认情况下,@ServletComponentScan 会从被注解类所在的包开始扫描。spring-doc.cadn.net.cn

配置访问日志记录

可以通过各自的命名空间为 Tomcat 和 Jetty 配置访问日志。spring-doc.cadn.net.cn

例如,以下设置使用自定义模式在 Tomcat 上记录访问日志。spring-doc.cadn.net.cn

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 中。

最后,Jetty 的访问日志也可以按如下方式配置:spring-doc.cadn.net.cn

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 文档。spring-doc.cadn.net.cn

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

如果你的应用程序运行在代理、负载均衡器之后,或在云环境中,请求信息(如主机、端口、协议方案等)可能会在传输过程中发生变化。 你的应用程序可能实际运行在 10.10.10.10:8080 上,但 HTTP 客户端应只看到 example.orgspring-doc.cadn.net.cn

RFC7239 “Forwarded Headers” 定义了 Forwarded HTTP 头;代理可以使用该头来提供有关原始请求的信息。 您可以配置应用程序读取这些头,并在创建链接以及通过 HTTP 302 响应、JSON 文档或 HTML 页面将其发送给客户端时自动使用这些信息。 此外,还存在一些非标准的头,例如 X-Forwarded-HostX-Forwarded-PortX-Forwarded-ProtoX-Forwarded-SslX-Forwarded-Prefixspring-doc.cadn.net.cn

如果代理添加了常用的 X-Forwarded-ForX-Forwarded-Proto 头部,只需将 server.forward-headers-strategy 设置为 NATIVE 即可支持这些头部。 使用此选项时,Web 服务器本身原生支持该功能;您可以查阅其具体文档以了解特定的行为。spring-doc.cadn.net.cn

如果这还不够,Spring Framework 为 Servlet 栈提供了 ForwardedHeaderFilter,并为响应式栈提供了 ForwardedHeaderTransformer。 您可以通过将 server.forward-headers-strategy 设置为 FRAMEWORK 在应用程序中使用它们。spring-doc.cadn.net.cn

如果你正在使用 Tomcat,并且在代理处终止 SSL,应将 server.tomcat.redirect-context-root 设置为 false。 这样可以在执行任何重定向前优先处理 X-Forwarded-Proto 请求头。
如果你的应用程序运行在受支持的云平台上,server.forward-headers-strategy 属性默认值为 NATIVE。 在所有其他情况下,默认值为 NONE

自定义 Tomcat 的代理配置

如果你使用 Tomcat,还可以额外配置用于传递“转发”信息的请求头名称,如下例所示:spring-doc.cadn.net.cn

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 添加一个条目来自定义该 Valve 的配置,如下例所示:spring-doc.cadn.net.cn

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 设置为空来信任所有代理(但在生产环境中不要这样做)。

您可以通过关闭自动配置(为此,请设置 server.forward-headers-strategy=NONE)并使用 WebServerFactoryCustomizer Bean 添加新的 Valve 实例,从而完全控制 Tomcat 的 RemoteIpValve 配置。spring-doc.cadn.net.cn

使用 Tomcat 启用多个连接器

您可以向 Connector 添加一个 TomcatServletWebServerFactory,从而支持多个连接器(包括 HTTP 和 HTTPS 连接器),如下例所示:spring-doc.cadn.net.cn

import org.apache.catalina.connector.Connector;

import org.springframework.boot.tomcat.servlet.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.addAdditionalConnectors(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.server.WebServerFactoryCustomizer
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory
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.addAdditionalConnectors(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 属性来启用,如下例所示:spring-doc.cadn.net.cn

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

使用 @ServerEndpoint 创建 WebSocket 端点

如果您想在使用了嵌入式容器的 Spring Boot 应用程序中使用 @ServerEndpoint,则必须声明单个 ServerEndpointExporter @Bean,如下例所示:spring-doc.cadn.net.cn

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。spring-doc.cadn.net.cn