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