嵌入式网页服务器
每个 Spring Boot 网页应用都包含一个嵌入式网页服务器。 该功能引发了许多作问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器。 本节将回答这些问题。
使用另一台网页服务器
许多 Spring Boot 启动程序默认包含嵌入式容器。
-
对于servlet栈应用,
Spring Boot启动网包含Tomcat,包括Spring靴启动猫,但你可以使用Spring靴-起动-Jetty相反。 -
对于响应式栈应用,
Spring BootStarters网流通过以下内容对反应堆Netty进行了分析Spring Boot器-反应堆-Netty,但你可以使用Spring靴启动猫或Spring靴-起动-Jetty相反。
切换到其他 HTTP 服务器时,你需要把默认依赖替换成你需要的。 为了帮助实现这一过程,Spring Boot 为每个支持的 HTTP 服务器提供独立的起始程序。
以下示例展示了如何排除Tomcat并将Jetty纳入春季MVC:
-
Maven
-
Gradle
<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"
}
如果你正在创建战争文件,也可以采用类似的方法,但必须指定提供的依赖关系:
-
Maven
-
Gradle
<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 服务器所需的位,Spring Boot 会自动启动它。
要禁用此行为,请配置WebApplicationType在你的application.properties如下例所示:
-
Properties
-
YAML
spring.main.web-application-type=none
spring:
main:
web-application-type: "none"
更改HTTP端口
在独立应用程序中,主HTTP端口默认为8080但可以设置为server.port(例如,在application.properties或作为系统属性)。
多亏了放松装订环境你也可以用SERVER_PORT(例如,作为作系统环境变量)。
完全关闭HTTP端点,但仍创建WebApplicationContext用server.port=-1(有时这样做对测试很有用)。
更多细节请参见“Spring Boot Features”部分中的“自定义嵌入式 Servlet 容器”,或ServerProperties类。
运行时发现HTTP端口
你可以从日志输出或WebServerApplicationContext通过其WebServer.
获取并确认已初始化的最佳方法是添加一个@Bean类型ApplicationListener<WebServerInitializedEvent>并在事件发布时将容器从事件中拉出。
使用@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
// ...
}
|
|
启用HTTP响应压缩
Jetty、Tomcat 和 Reactor Netty 支持 HTTP 响应压缩。
它可以在application.properties如下:
-
Properties
-
YAML
server.compression.enabled=true
server:
compression:
enabled: true
默认情况下,响应长度必须至少为2048字节才能进行压缩。
你可以通过设置server.compression.min-response-size财产。
默认情况下,只有当回复内容类型符合以下几种时,才会被压缩:
-
文本/HTML -
文本/XML -
文本/纯文字 -
文本/CSS -
文本/JavaScript -
应用程序/JavaScript -
application/json -
application/xml
你可以通过设置server.compression.mime-types财产。
配置SSL
SSL 可以通过设置各种server.ssl.*通常在application.properties或application.yaml.
看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 不支持通过以下方式配置 HTTP 连接器和 HTTPS 连接器application.properties.
如果你想同时拥有两个,你需要用程序方式配置其中一个。
我们推荐使用application.properties配置HTTPS,因为HTTP连接器在编程中更容易配置。
使用 PEM 编码文件
你可以用PEM编码的文件代替Java KeyStore文件。
你应该尽可能使用 PKCS#8 密钥文件。
PEM编码的PKCS#8密钥文件以a-----私钥开始-----或-----开始加密私钥-----页眉。
如果你有其他格式的文件,比如 PKCS#1 (-----开始RSA私钥-----)或SEC 1(-----开始EC私钥-----),你可以用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 捆绑包
或者,也可以将SSL信任材料配置为SSL捆绑包,并应用到Web服务器,如本示例所示:
-
Properties
-
YAML
server.port=8443
server.ssl.bundle=example
server:
port: 8443
ssl:
bundle: "example"
|
这 这 |
配置服务器名称指示
Tomcat和Netty可以配置为使用独特的SSL信任材料,以支持服务器名称指示(SNI)。 Jetty 不支持 SNI 配置,但如果 Jetty 获得了多个证书,可以自动设置 SNI。
假设SSL捆绑包命名为Web,Web-Alt1和Web-Alt2配置完成后,可以使用以下配置将每个套件分配给由嵌入式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将用于默认主机,以及任何支持 SNI 的客户端。
如果有的话,必须配置这个默认捆绑包server.ssl.server-name-bundles是配置好的。
配置HTTP/2
你可以在 Spring Boot 应用中启用 HTTP/2 支持,server.http2.enabled配置属性。
双H2(通过 TLS 的 HTTP/2)以及H2C(HTTP/2 over TCP)都被支持。
使用H2,也必须启用SSL。
当未启用SSL时,H2C将被使用。
例如,你可能想使用H2C当你的应用运行在一个正在执行TLS终止的代理服务器后面。
HTTP/2 与 Tomcat 合作
Spring Boot默认搭载支持的Tomcat 11.0.x版本H2C和H2直接开箱。
或者,你可以使用libtcnative为H2支持库及其依赖安装在主机作系统上。
库目录必须(如果尚未提供)必须提供给JVM库路径。
你可以用JVM参数来实现,比如-Djava.library.path=/usr/local/opt/tomcat-native/lib.
更多内容请参见官方Tomcat文档。
HTTP/2 与 Jetty
对于HTTP/2支持,Jetty需要额外的org.eclipse.jetty.http2:jetty-http2-serverDependency。
使用H2C不需要其他依赖关系。
使用H2根据部署情况,您还需要选择以下依赖之一:
-
org.eclipse.jetty:jetty-alpn-java-server以利用JDK内置的支持 -
org.eclipse.jetty:jetty-alpn-conscrypt-server以及Conscrypt图书馆
HTTP/2 与 Reactor Netty
这Spring Boot网通启动默认使用 Reactor Netty 作为服务器。
反应堆Netty支撑H2C和H2直接开箱。
为了实现最佳运行时性能,该服务器还支持H2使用原生库。
要实现这一点,你的应用需要额外的依赖。
Spring Boot 管理该版本io.netty:netty-tcnative-boringssl-static“Uber Jar”,包含适用于所有平台的本地库。
开发者可以通过分类器选择只导入所需的依赖(参见Netty官方文档)。
配置网页服务器
通常,你应该先考虑使用众多可用的配置密钥之一,并通过添加新的条目来自定义你的 Web 服务器application.properties或application.yaml文件。
参见“发现外部属性的内置选项”。
这服务器。*命名空间在这里非常有用,它包含以下命名空间服务器.tomcat.*,server.jetty.*以及其他服务器专用功能。
参见常见应用属性列表。
前面的部分已经涵盖了许多常见用例,如压缩、SSL 或 HTTP/2。
然而,如果没有适合你用例的配置密钥,你应该查看WebServerFactoryCustomizer.
你可以声明这样的组件,并访问与你选择相关的服务器工厂:你应为所选服务器选择变体(Tomcat、Jetty、Reactor Netty)和所选的网页栈(servlet 或 reactive)。
下面的例子是 Tomcat,其中Spring Boot启动网(servlet 栈):
-
Java
-
Kotlin
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 内部利用该基础设施自动配置服务器。
自动配置WebServerFactoryCustomizerBeans的阶数为0除非有明确的顺序说明,否则会在任何用户自定义的定制器之前被处理。 |
一旦你获得了访问权限WebServerFactory使用自定义器,你可以用它配置特定部分,比如连接器、服务器资源或服务器本身——所有这些都使用服务器专用的 API。
此外,Spring Boot还提供:
| 服务器 | Servlet 堆栈 | 响应式栈 |
|---|---|---|
Tomcat |
||
Jetty |
||
反应器 |
无 |
作为最后的手段,你也可以申报自己的WebServerFactory豆子,会覆盖春季靴提供的。
这样做后,自动配置的自定义器仍然会应用到你的自定义工厂上,所以请谨慎使用该选项。
向应用程序添加 Servlet、过滤器或监听器
在servlet栈应用中,即Spring Boot启动网,有两种加法servlet,Filter,ServletContextListener以及 Servlet API 支持的其他监听器:
使用春豆添加 servlet、filter(Filter)或监听器(listener),使用 Spring Bean
要添加一个servlet,Filter,或servlet。*听者使用春季豆时,你必须提供@Bean它的定义。
当你想注入配置或依赖时,这样做非常有用。
但你必须非常小心,避免它们导致过多其他豆子被急于初始化,因为它们必须在应用生命周期的早期就安装到容器中。
(例如,让他们依赖你的情况并不是个好主意数据来源或JPA配置。)
你可以通过在首次使用时懒惰地初始化豆子来绕过这些限制,而不是在初始化时。
对于Filter和servlet,你还可以通过添加FilterRegistrationBean或者ServletRegistrationBean而不是或附加于底层组件。
你也可以使用@ServletRegistration和@FilterRegistration作为基于注释的替代方案ServletRegistrationBean和FilterRegistrationBean.
|
如果没有 |
像其他春季豆一样,你可以定义Servlet滤豆的顺序;请务必查看“注册servlets、过滤器和听众为春豆”部分。
禁用servlet或Filter的注册
-
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、过滤器和监听器
@WebServlet,@WebFilter和@WebListener注释类可以通过注释@Configuration类为@ServletComponentScan并指定包含你想注册组件的包。
默认情况下,@ServletComponentScan从注释类包中扫描。
配置访问日志
访问日志可以通过Tomcat和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基础目录的目录。
默认情况下,原木目录是临时目录,所以你可能需要修复Tomcat的基础目录,或者使用日志的绝对路径。
在上述例子中,日志在我的公猫/木头相对于应用程序的工作目录。 |
最后,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“转发头”定义了转发HTTP 头部;代理可以使用该报头来提供关于原始请求的信息。
你可以配置应用读取这些头部,并在创建链接并发送给客户端的HTTP 302响应、JSON文档或HTML页面时自动使用这些信息。
还有一些非标准的头部,比如转发主机,X-转发端口,X-转发-原始,X-转发-SSL(转发-SSL)和X-转发前缀.
如果代理添加常用的转发给和X-转发-原始页眉,设置server.forward-headers-strategy自本地足以支持这些。
有了这个选项,Web服务器本身就原生支持这一功能;你可以查看他们的具体文档,了解具体行为。
如果这还不够,Spring Framework 为 servlet 栈提供了 ForwardedHeaderFilter 和响应式栈的 ForwardedHeaderTransformer。
你可以在应用中设置它们server.forward-headers-strategy自框架.
如果你用的是Tomcat并且在代理处终止了SSL,server.tomcat.redirect-context-root应设置为false.
这使得X-转发-原始在执行任何重定向之前,必须尊重该头部。 |
如果你的应用运行在支持的云平台上,server.forward-headers-strategy性质默认为本地.
在其他情况下,默认为没有. |
自定义Tomcat代理配置
如果你使用 Tomcat,还可以配置用于承载“转发”信息的头部名称,如下示例所示:
-
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}"
你可以通过设置内部代理清空(但不要在生产环境中进行)。 |
你可以完全控制Tomcat的配置远程IpValve通过关闭自动一键(要关闭,设置)server.forward-headers-strategy=NONE)并通过使用WebServerFactoryCustomizer豆。
用Tomcat启用多个连接器
你可以添加一个连接器前往TomcatServletWebServerFactory,允许多个连接器,包括HTTP和HTTPS连接器,如下示例所示:
-
Java
-
Kotlin
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注册库
Embedded Tomcat 的 MBean 注册表默认被禁用。
这最大限度地减少了Tomcat的内存占用。
例如,如果你想使用 Tomcat 的 MBeans,以便 Micrometer 用它们来曝光度量,你必须使用server.tomcat.mbeanregistry.enabled以实现这一点的性质,如下例所示:
-
Properties
-
YAML
server.tomcat.mbeanregistry.enabled=true
server:
tomcat:
mbeanregistry:
enabled: true
使用 @ServerEndpoint 创建 WebSocket 端点
如果你想使用@ServerEndpoint在使用嵌入式容器的 Spring Boot 应用中,必须声明一个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()
}
}
前例中所示的豆子记录为任意@ServerEndpoint带有底层WebSocket容器的注释豆。
当部署到独立的 servlet 容器时,该角色由 servlet 容器初始化器执行,并且ServerEndpointExporter豆子不是必须的。