Embedded Web Servers
每个 Spring Boot Web 应用程序都包含一个嵌入式 Web 服务器。此功能导致了许多操作问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器。本节将回答这些问题。
Use Another Web Server
许多 Spring Boot starter 都包含默认的嵌入式容器。
-
对于 servlet 堆栈应用程序,
spring-boot-starter-web通过包含spring-boot-starter-tomcat包含 Tomcat,但你可以改用spring-boot-starter-jetty或spring-boot-starter-undertow。 -
对于反应堆堆栈应用程序,
spring-boot-starter-webflux通过包含spring-boot-starter-reactor-netty包含 Reactor Netty,但你可以改用spring-boot-starter-tomcat、spring-boot-starter-jetty或spring-boot-starter-undertow。
切换至其他 HTTP 服务器时,你需要用自己需要的默认依赖项替换那些默认依赖项。Spring Boot 为每个受支持的 HTTP 服务器提供了一个单独的 starter,以帮助完成此过程。
以下 Maven 示例演示了如何排除 Tomcat 并添加 Jetty 以用于 Spring MVC:
<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 示例配置了必需的依赖项和一个 {url-gradle-docs}/resolution_rules.html#sec:module_replacement[模块替换] 以便使用 Undertow 替换 Reactor Netty 以用于 Spring WebFlux:
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")
}
}
}
|
|
Disabling the Web Server
如果类路径包含启动 Web 服务器的必需部分,Spring Boot 会自动启动它。要禁用此行为,可在 application.properties 中配置 WebApplicationType,如下例所示:
spring:
main:
web-application-type: "none"
Change the HTTP Port
在独立应用程序中,主要 HTTP 端口默认为 8080,但可以用 configprop:server.port[] 设置(例如在 application.properties 中或作为系统属性)。由于 Environment 值的约束已被弱化,你还可以使用 configprop:server.port[format=envvar](例如作为操作系统环境变量)。
要完全关闭 HTTP 端点但仍然创建 WebApplicationContext,请使用 server.port=-1(这样做有时对于测试很有用)。
有关更多详细信息,请参阅“Spring Boot 功能部分中的 “Customizing Embedded Servlet Containers” 或 {code-spring-boot-autoconfigure-src}/web/ServerProperties.java[ServerProperties] 源代码。
Discover the HTTP Port at Runtime
可以通过日志输出或通过其 WebServer 从 WebServerApplicationContext 访问服务器正在运行的端口。最佳做法是添加类型为 ApplicationListener<WebServerInitializedEvent> 的 @Bean,并在发布事件时将容器从中移除,以便获取端口并确保已初始化。
使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) 的测试还可以通过使用 @LocalServerPort 注释将实际端口注入字段,如下例所示:
|
|
Enable HTTP Response Compression
HTTP 响应压缩受 Jetty、Tomcat、Reactor Netty 和 Undertow 支持。它可以在 application.properties 中启用,如下所示:
server:
compression:
enabled: true
默认情况下,响应长度必须至少达到 2048 个字节才能执行压缩。你可以通过设置 configprop:server.compression.min-response-size[] 属性来配置此行为。
默认情况下,只有相应内容类型为以下类型之一时,才会对其进行压缩:
-
text/html -
text/xml -
text/plain -
text/css -
text/javascript -
application/javascript -
application/json -
application/xml
你可以通过设置 configprop:server.compression.mime-types[] 属性来配置此行为。
Configure SSL
可以通过设置各种 server.ssl.* 属性来以声明的方式配置 SSL,通常在 application.properties 或 application.yaml 中设置。以下示例演示了使用 Java KeyStore 文件设置 SSL 属性:
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 连接器更容易通过编程方式进行配置。
Using PEM-encoded files
您可以使用 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 属性:
server:
port: 8443
ssl:
certificate: "classpath:my-cert.crt"
certificate-private-key: "classpath:my-cert.key"
trust-certificate: "classpath:ca-cert.crt"
或者,SSL 信任材料可以在 SSL bundle 中进行配置,并如示例所示应用于 Web 服务器:
server:
port: 8443
ssl:
bundle: "example"
|
|
有关所有受支持属性的详情,请参阅 {code-spring-boot-src}/web/server/Ssl.java[Ssl]。
Configure HTTP/2
您可以使用 configprop:server.http2.enabled[] 配置属性在 Spring Boot 应用程序中启用 HTTP/2 支持。h2(通过 TLS 进行的 HTTP/2)和 h2c(通过 TCP 进行的 HTTP/2)均受支持。要使用 h2,还必须启用 SSL。当 SSL 未启用时,将使用 h2c。例如,当您的应用程序是 running behind a proxy server 并执行 TLS 终结时,您可能希望使用 h2c。
HTTP/2 With Tomcat
Spring Boot 默认与 Tomcat 10.1.x 捆绑,该 Tomcat 开箱即用地支持 h2c 和 h2。或者,如果您在主机操作系统上安装了该库及其依赖项,可以使用 libtcnative 来获得 h2 支持。
如果尚未将库目录提供给 JVM 库路径,则必须提供它。可以使用 -Djava.library.path=/usr/local/opt/tomcat-native/lib 这样的 JVM 参数来实现此目的。有关此内容,请参阅 {url-tomcat-docs}/apr.html[官方 Tomcat 文档]。
HTTP/2 With Jetty
对于 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-server和 Conscrypt library
HTTP/2 With Reactor Netty
spring-boot-webflux-starter 默认使用 Reactor Netty 作为服务器。Reactor Netty 开箱即用地支持 h2c 和 h2。为了获得最佳运行时性能,此服务器还支持具有本机库的 h2。为了启用该库,您的应用程序需要具有附加的依赖项。
Spring Boot 管理用于 io.netty:netty-tcnative-boringssl-static 的“超级 jar”的版本,该“超级 jar”包含针对所有平台的本机库。开发人员可以选择仅使用分类器导入必需的依赖项(请参阅 the Netty official documentation)。
Configure the Web Server
通常,您首先应考虑使用众多可用的配置密钥之一,并通过在 application.properties 或 application.yaml 文件中添加新条目来自定义 Web 服务器。请参阅 “Discover Built-in Options for External Properties”)。server. namespace is quite useful here, and it includes namespaces like server.tomcat.、server.jetty.* 和其他,用于与服务器相关的功能。请参阅 Common Application Properties 列表。
前面的章节已涵盖了许多常见的使用案例,例如压缩、SSL 或 HTTP/2。但是,如果不存在适用于您使用案例的配置密钥,那么您应该查看 WebServerFactoryCustomizer。您可以声明这样的组件,并获得针对您选择的合适的服务器工厂:您应该为所选的服务器(Tomcat、Jetty、Reactor Netty、Undertow)和所选的 Web 堆栈(servlet 或 reactive)选择变体。
以下示例适用于 Tomcat 和 spring-boot-starter-web(servlet 堆栈):
|
Spring Boot 在内部使用该基础设施来自动配置服务器。自动配置的 |
一旦您使用定制器访问了 WebServerFactory,您就可以使用它为特定部分、如连接器、服务器资源或服务器本身配置,所有这些都使用特定于服务器的 API。
此外,Spring Boot 提供:
| Server | Servlet stack | Reactive stack |
|---|---|---|
Tomcat |
|
|
Jetty |
|
|
Undertow |
|
|
Reactor |
N/A |
|
作为最后手段,您也可以声明自己的 WebServerFactory Bean,它将覆盖 Spring Boot 提供的 Bean。当您这样做时,自动配置的定制器仍会被应用到您的自定义工厂中,因此要小心使用该选项。
Add a Servlet, Filter, or Listener to an Application
在 servlet 堆栈应用程序中,即带有 spring-boot-starter-web 的,有两种方法可以向您的应用程序添加 Servlet、Filter、ServletContextListener 以及 Servlet API 支持的其他侦听器:
Add a Servlet, Filter, or Listener by Using a Spring Bean
要使用 Spring Bean 添加 Servlet、Filter 或 Servlet *Listener,您必须提供其 @Bean 定义。当您想注入配置或依赖关系时,这样做非常有用。但是,您必须非常小心,以避免过早地初始化许多其他 Bean,因为它们必须在应用程序生命周期的早期安装到容器中。(例如,让他们依赖您的 DataSource 或 JPA 配置不是一个好主意。)您可以在首次使用时而不是在初始化时懒惰地初始化 Bean 来解决此类限制。
在过滤器和 servlet 的情况下,您还可以添加映射和初始化参数,方法是添加 FilterRegistrationBean 或 ServletRegistrationBean,而不是或除了基础组件。
|
如果过滤器注册中未指定 |
与任何其他 Spring Bean 一样,您也可以定义 servlet 过滤器 Bean 的顺序;请务必查看 “Registering Servlets, Filters, and Listeners as Spring Beans” 部分。
Disable Registration of a Servlet or Filter
与 described earlier 一样,任何 Servlet 或 Filter Bean 都将自动注册到 servlet 容器中。要禁用特定 Filter 或 Servlet Bean 的注册,请为其创建注册 Bean 并将其标记为禁用,如下例所示:
Configure Access Logging
可以通过其各自的名称空间为 Tomcat、Undertow 和 Jetty 配置访问日志。
例如,以下设置使用 {url-tomcat-docs}/config/valve.html#Access_Logging[自定义模式] 在 Tomcat 上记录访问。
server:
tomcat:
basedir: "my-tomcat"
accesslog:
enabled: true
pattern: "%t %a %r %s (%D microseconds)"
|
日志的默认位置是 Tomcat 基本目录相对路径的 |
Undertow 的访问日志记录可以按照类似的方式进行配置,如下例所示:
server:
undertow:
accesslog:
enabled: true
pattern: "%t %a %r %s (%D milliseconds)"
options:
server:
record-request-start-time: true
请注意,除了启用访问日志记录和配置其模式外,还启用了记录请求开始时间。在访问日志模式中包含响应时间 (%D) 时需要这样做。日志存储在应用程序工作目录相对路径的 logs 目录中。您可以通过设置 configprop:server.undertow.accesslog.dir[] 属性来自定义此位置。
最后,还可以如下配置 Jetty 的访问日志记录:
server:
jetty:
accesslog:
enabled: true
filename: "/var/log/jetty-access.log"
默认情况下,会将日志重定向至 System.err。有关更多详细信息,请参阅 Jetty 文档。
Running Behind a Front-end Proxy Server
如果你的应用程序在代理、负载均衡器或云端后面运行,请求信息(如主机、端口、方案……)可能会发生更改。你的应用程序可能在 10.10.10.10:8080 上运行,但 HTTP 客户端只能看到 example.org。
RFC7239 "Forwarded Headers" 定义了 Forwarded HTTP 标头;代理可使用此标头提供有关原始请求的信息。你可以配置应用程序来读取这些标头,并在 HTTP 302 响应、JSON 文档或 HTML 页面中创建链接并将其发送给客户端时自动使用该信息。还有一些非标准标头,如 X-Forwarded-Host、X-Forwarded-Port、X-Forwarded-Proto、X-Forwarded-Ssl 和 X-Forwarded-Prefix。
如果代理添加常用的 X-Forwarded-For 和 X-Forwarded-Proto 标头,将 server.forward-headers-strategy 设置为 NATIVE 足以支持这些标头。通过此选项,Web 服务器本身会本机化支持此功能;你可以查阅其特定文档,了解具体行为。
如果这还不够,Spring Framework 会为 servlet 堆栈提供一个 {url-spring-framework-docs}/web/webmvc/filters.html#filters-forwarded-headers[ForwardedHeaderFilter],为响应式堆栈提供一个 {url-spring-framework-docs}/web/webflux/reactive-spring.html#webflux-forwarded-headers[ForwardedHeaderTransformer]。你可以将它们用于你的应用程序,方法是将 configprop:server.forward-headers-strategy[] 设置为 FRAMEWORK。
|
如果你正在使用 Tomcat 并终止代理处的 SSL,则应该将 configprop:server.tomcat.redirect-context-root[] 设置为 |
|
如果你的应用程序在 Cloud Foundry、Heroku 或 Kubernetes 中运行,configprop:server.forward-headers-strategy[] 属性默认为 |
Customize Tomcat’s Proxy Configuration
如果你使用 Tomcat,你可以另外配置用于承载 “forwarded” 信息的标头的名称,如下面的示例所示:
server:
tomcat:
remoteip:
remote-ip-header: "x-your-remote-ip-header"
protocol-header: "x-your-protocol-header"
Tomcat 还会配置一个用于匹配要信任的内部代理的正则表达式。有关其默认值,请参阅附录中的 configprop:server.tomcat.remoteip.internal-proxies[ 条目。你可以通过向 application.properties 中添加条目来自定义阀值的配置,如下面的示例所示:
server:
tomcat:
remoteip:
internal-proxies: "192\\.168\\.\\d{1,3}\\.\\d{1,3}"
|
你可以将 |
你可以通过关闭自动功能来完全控制 Tomcat 的 RemoteIpValve 配置(为此,请设置 server.forward-headers-strategy=NONE),并使用 WebServerFactoryCustomizer bean 添加新阀值实例。
Enable Multiple Connectors with Tomcat
你可以向 TomcatServletWebServerFactory 中添加一个 org.apache.catalina.connector.Connector,该 org.apache.catalina.connector.Connector 可以允许多个连接器,包括 HTTP 和 HTTPS 连接器,如下面的示例所示:
Enable Tomcat’s MBean Registry
默认情况下,禁用 Embedded Tomcat 的 MBean 注册表。这会最大程度减少 Tomcat 的内存占用。如果你希望使用 Tomcat 的 MBean(例如以使 Micrometer 可以使用它们来公开指标),你必须使用 configprop:server.tomcat.mbeanregistry.enabled[] 属性来执行此操作,如下面的示例所示:
server:
tomcat:
mbeanregistry:
enabled: true