- 3.1. 使用其他Web服务器
- 3.2. 禁用Web服务器
- 3.3. 更改HTTP端口
- 3.4. 使用随机未分配的HTTP端口
- 3.5. 在运行时发现HTTP端口
- 3.6. 启用HTTP响应压缩
- 3.7. 配置SSL
- 3.8. 配置HTTP / 2
- 3.9. 配置Web服务器
- 3.10. 将Servlet,过滤器或侦听器添加到应用程序
- 3.11. 配置访问日志
- 3.12. 在前端代理服务器后面运行
- 3.13. 使用Tomcat启用多个连接器
- 3.14. 使用Tomcat的LegacyCookieProcessor
- 3.15. 启用Tomcat的MBean注册表
- 3.16. 使用Undertow启用多个侦听器
- 3.17. 使用@ServerEndpoint创建WebSocket端点
每个Spring Boot Web应用程序都包含一个嵌入式Web服务器。此功能导致许多方法问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器。本节回答这些问题。
3.1. 使用其他Web服务器
许多Spring Boot启动器都包含默认的嵌入式容器。
- 对于servlet堆栈应用程序,通过
spring-boot-starter-web
包括来包括Tomcatspring-boot-starter-tomcat
,但是您可以使用spring-boot-starter-jetty
或spring-boot-starter-undertow
代替。 - 对于反应栈的应用,
spring-boot-starter-webflux
包括反应堆的Netty通过包括spring-boot-starter-reactor-netty
,但你可以使用spring-boot-starter-tomcat
,spring-boot-starter-jetty
或spring-boot-starter-undertow
代替。
切换到其他HTTP服务器时,您需要将默认依赖项交换为所需的依赖项。为了帮助完成此过程,Spring Boot为每个受支持的HTTP服务器提供了一个单独的启动器。
以下Maven示例显示了如何排除Tomcat并包括Jetty for Spring MVC:
<properties>
<servlet-api.version>3.1.0</servlet-api.version>
</properties>
<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>
Servlet API的版本已被覆盖,因为与Tomcat 9和Undertow 2.0不同,Jetty 9.4不支持Servlet 4.0。 | |
---|---|
以下Gradle示例显示了如何使用Undertow代替Spring WebFlux的Reactor Netty:
configurations.all {
resolutionStrategy.dependencySubstitution.all { dependency ->
if (dependency.requested instanceof ModuleComponentSelector && dependency.requested.module == 'spring-boot-starter-reactor-netty') {
dependency.useTarget("org.springframework.boot:spring-boot-starter-undertow:$dependency.requested.version", 'Use Undertow instead of Reactor Netty')
}
}
}
dependencies {
compile 'org.springframework.boot:spring-boot-starter-webflux'
// ...
}
spring-boot-starter-reactor-netty 使用WebClient 该类是必需的,因此即使您需要包括其他HTTP服务器,也可能需要保持对Netty的依赖。 |
|
---|---|
3.2. 禁用Web服务器
如果您的类路径包含启动Web服务器所需的位,则Spring Boot将自动启动它。要禁用此行为,请WebApplicationType
在中配置application.properties
,如以下示例所示:
物产
Yaml
spring.main.web-application-type=none
3.3. 更改HTTP端口
在独立应用程序中,主HTTP端口默认为,8080
但可以使用server.port
(例如,在application.properties
System属性中或作为System属性)进行设置。由于轻松地绑定了Environment
值,因此还可以使用SERVER_PORT
(例如,作为OS环境变量)。
要完全关闭HTTP端点但仍创建一个WebApplicationContext
,请使用server.port=-1
(这样做有时对测试很有用)。
有关更多详细信息,请参阅“ Spring Boot功能”部分中的“ spring-boot-features.html ”或ServerProperties
源代码。
3.4. 使用随机未分配的HTTP端口
要扫描可用端口(使用OS本机来防止冲突),请使用server.port=0
。
3.5. 在运行时发现HTTP端口
您可以从日志输出或WebServerApplicationContext
通过其端口访问服务器运行的端口WebServer
。最好的方法是确保它已被初始化,是添加一个@Bean
typeApplicationListener<WebServerInitializedEvent>
并在事件发布时将其从事件中拉出。
使用的测试@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
还可以通过使用@LocalServerPort
批注将实际端口注入字段中,如以下示例所示:
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class MyWebIntegrationTests {
@LocalServerPort
int port;
// ...
}
@LocalServerPort 是的元注释@Value("${local.server.port}") 。不要尝试在常规应用程序中注入端口。如我们所见,仅在初始化容器之后才设置该值。与测试相反,应早处理应用程序代码回调(在值实际可用之前)。 |
|
---|---|
3.6. 启用HTTP响应压缩
Jetty,Tomcat和Undertow支持HTTP响应压缩。可以在中启用它application.properties
,如下所示:
物产
Yaml
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
属性来配置此行为。
3.7. 配置SSL
可以通过设置各种server.ssl.*
属性来声明性地配置SSL ,通常在application.properties
或中application.yml
。以下示例显示了在中设置SSL属性application.properties
:
物产
Yaml
server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
server.ssl.key-password=another-secret
有关Ssl
所有受支持属性的详细信息,请参见。
使用上述示例的配置意味着应用程序不再在端口8080上支持纯HTTP连接器。SpringBoot不支持通过进行HTTP连接器和HTTPS连接器的配置application.properties
。如果要同时拥有两者,则需要以编程方式配置它们之一。我们建议您使用application.properties
HTTPS进行配置,因为HTTP连接器是两者中以编程方式配置的比较容易的方法。
3.8. 配置HTTP / 2
您可以使用server.http2.enabled
配置属性在Spring Boot应用程序中启用HTTP / 2支持。该支持取决于所选的Web服务器和应用程序环境,因为并非所有JDK8版本都立即支持该协议。
Spring Boot不建议使用h2c HTTP / 2协议的明文版本。因此,以下各节要求您首先配置SSL。如果仍然选择使用h2c ,则可以查看专用部分。 |
|
---|---|
3.8.1. Tomcat的HTTP / 2
默认情况下,Spring Boot随Tomcat 9.0.x一起提供,当使用JDK 9或更高版本时,Tomcat 9.0.x支持HTTP / 2。另外,如果libtcnative
库及其依赖项已安装在主机操作系统上,则可以在JDK 8上使用HTTP / 2 。
如果没有,则必须使库目录可用于JVM库路径。您可以使用JVM参数(例如)来执行此操作-Djava.library.path=/usr/local/opt/tomcat-native/lib
。有关更多信息,请参见Tomcat官方文档。
在没有该本机支持的情况下,在JDK 8上启动Tomcat 9.0.x会记录以下错误:
错误8787-[[main] oacoyote.http11.Http11NioProtocol:[h2]的升级处理程序[org.apache.coyote.http2.Http2Protocol]仅支持通过ALPN进行升级,但已为[“ https-jsse-nio”配置-8443“]连接器不支持ALPN。
此错误不是致命错误,并且该应用程序仍以HTTP / 1.1 SSL支持开头。
3.8.2. HTTP / 2与码头
对于HTTP / 2支持,Jetty需要附加的org.eclipse.jetty.http2:http2-server
依赖关系。现在,根据您的部署,还需要选择其他依赖项:
org.eclipse.jetty:jetty-alpn-java-server
适用于在JDK9 +上运行的应用程序org.eclipse.jetty:jetty-alpn-openjdk8-server
适用于在JDK8u252 +上运行的应用程序org.eclipse.jetty:jetty-alpn-conscrypt-server
和没有JDK要求的Conscrypt库
3.8.3. HTTP / 2和Reactor Netty
在spring-boot-webflux-starter
默认情况下,反应堆的Netty作为服务器使用。使用JDK 9或更高版本的JDK支持,可以将Reactor Netty配置为HTTP / 2。对于JDK 8环境,或为了获得最佳的运行时性能,此服务器还支持带有本机库的HTTP / 2。为此,您的应用程序需要具有其他依赖关系。
Spring Boot管理io.netty:netty-tcnative-boringssl-static
“超级罐”的版本,其中包含所有平台的本机库。开发人员可以选择使用分类器仅导入所需的依赖项(请参阅Netty官方文档)。3.8.4. 带有Undertow的HTTP / 2
从Undertow 1.4.0+开始,在JDK8上没有任何其他要求就支持HTTP / 2。3.8.5. 支持服务器的HTTP / 2明文
要启用具有明文支持的HTTP / 2,您需要将该server.http2.enabled
属性设置为false
,而是应用特定于您选择的服务器的定制程序:
对于Tomcat,我们需要添加一个升级协议:
对于Jetty,我们需要向现有连接器添加连接工厂:@Bean
public TomcatConnectorCustomizer connectorCustomizer() {
return (connector) -> connector.addUpgradeProtocol(new Http2Protocol());
}
对于Netty,我们需要添加@Bean
public JettyServerCustomizer serverCustomizer() {
return (server) -> {
HttpConfiguration configuration = new HttpConfiguration();
configuration.setSendServerVersion(false);
Arrays.stream(server.getConnectors())
.filter(connector -> connector instanceof ServerConnector)
.map(ServerConnector.class::cast)
.forEach(connector -> {
connector.addConnectionFactory(new HTTP2CServerConnectionFactory(configuration));
});
};
}
h2c
作为受支持的协议:
对于Undertow,我们需要启用HTTP2选项:@Bean
public NettyServerCustomizer serverCustomizer() {
return (server) -> server.protocol(HttpProtocol.H2C);
}
@Bean
public UndertowBuilderCustomizer builderCustomizer() {
return (builder) -> {
builder.setServerOption(ENABLE_HTTP2, true);
};
}
3.9. 配置Web服务器
通常,您应该首先考虑使用许多可用的配置键之一,并通过在您的application.properties
(或application.yml
,或环境等)中添加新条目来自定义Web服务器。请参阅“发现外部属性的内置选项”。该server.*
命名空间是非常有用的在这里,它包括命名空间一样server.tomcat.*
,server.jetty.*
和其他人,对服务器的特定功能。请参阅appendix-application-properties.html的列表。
前面的部分已经介绍了许多常见的用例,例如压缩,SSL或HTTP / 2。但是,如果您的用例不存在配置密钥,则应查看WebServerFactoryCustomizer
。您可以声明一个这样的组件,并访问与您选择的服务器相关的工厂:您应该为所选服务器(Tomcat,Jetty,Reactor Netty,Undertow)和所选Web堆栈(Servlet或Reactive)选择变体。
以下示例适用于具有spring-boot-starter-web
(Servlet堆栈)的Tomcat :
此外,Spring Boot还提供:@Component
public class MyTomcatWebServerCustomizer
implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
// customize the factory here
}
}
服务器 | Servlet堆栈 | 反应堆 |
---|---|---|
雄猫 | TomcatServletWebServerFactory |
TomcatReactiveWebServerFactory |
码头 | JettyServletWebServerFactory |
JettyReactiveWebServerFactory |
底拖 | UndertowServletWebServerFactory |
UndertowReactiveWebServerFactory |
反应堆 | 不适用 | NettyReactiveWebServerFactory |
一旦访问了WebServerFactory
,就可以经常向其添加定制程序,以配置特定的部分,例如连接器,服务器资源或服务器本身-全部使用服务器特定的API。
最后,您还可以声明自己的WebServerFactory
组件,该组件将覆盖Spring Boot提供的组件。在这种情况下,您不能再依赖server
命名空间中的配置属性。
3.10. 将Servlet,过滤器或侦听器添加到应用程序
在一个servlet栈的应用,即用spring-boot-starter-web
,有两种方法可以添加Servlet
,Filter
,ServletContextListener
,和由Servlet API到您的应用程序支持的其他听众:
- 使用Spring Bean添加Servlet,过滤器或侦听器
- 使用类路径扫描添加Servlet,过滤器和侦听器
3.10.1. 使用Spring Bean添加Servlet,过滤器或侦听器
要添加Servlet
,Filter
或servlet*Listener
使用的Spring bean,你必须提供一个@Bean
它的定义。当您要注入配置或依赖项时,这样做非常有用。但是,您必须非常小心,以免引起过多其他bean的急切初始化,因为必须在应用程序生命周期的早期就将它们安装在容器中。(例如,让它们依赖于您的DataSource
或JPA配置不是一个好主意。)您可以通过在第一次使用bean时而不是在初始化时进行延迟初始化来解决这些限制。
在的情况下Filters
和Servlets
,还可以通过添加添加映射和初始化参数FilterRegistrationBean
或ServletRegistrationBean
代替或除了下面的部件。
如果dispatcherType 在过滤器注册上未指定no ,REQUEST 则使用。这与Servlet规范的默认调度程序类型一致。 |
|
---|---|
像其他任何Spring bean一样,您可以定义Servlet过滤器bean的顺序。请确保检查“ spring-boot-features.html ”部分。
禁用Servlet或过滤器的注册
正如前面所述,任何Servlet
或Filter
豆与servlet容器自动注册。要禁用特定Filter
或Servlet
bean的注册,请为其创建注册bean并将其标记为已禁用,如以下示例所示:
@Bean
public FilterRegistrationBean registration(MyFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
3.10.2. 使用类路径扫描添加Servlet,过滤器和侦听器
@WebServlet
,,@WebFilter
和带@WebListener
注释的类可以通过向注释一个@Configuration
类@ServletComponentScan
并指定包含要注册的组件的包来自动向嵌入式servlet容器注册。默认情况下,@ServletComponentScan
从带注释的类的包进行扫描。
3.11. 配置访问日志
可以通过它们各自的名称空间为Tomcat,Undertow和Jetty配置访问日志。
例如,以下设置使用自定义模式记录对Tomcat的访问。
物产
Yaml
server.tomcat.basedir=my-tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a %r %s (%D ms)
日志的默认位置是logs 相对于Tomcat基本目录的目录。默认情况下,该logs 目录是一个临时目录,因此您可能需要修复Tomcat的基本目录或为日志使用绝对路径。在前面的示例中,日志my-tomcat/logs 相对于应用程序的工作目录可用。 |
|
---|---|
可以用类似的方式配置Undertow的访问日志,如以下示例所示:
物产
Yaml
server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=%t %a %r %s (%D ms)
日志存储在logs
相对于应用程序工作目录的目录中。您可以通过设置server.undertow.accesslog.dir
属性来自定义此位置。
最后,Jetty的访问日志也可以配置如下:
物产
Yaml
server.jetty.accesslog.enabled=true
server.jetty.accesslog.filename=/var/log/jetty-access.log
默认情况下,日志重定向到System.err
。有关更多详细信息,请参见Jetty文档。
3.12. 在前端代理服务器后面运行
如果您的应用程序是在代理,负载均衡器之后或在云中运行的,则请求信息(例如主机,端口,方案等)可能会随之变化。您的应用程序可能正在运行10.10.10.10:8080
,但是HTTP客户端只能看到example.org
。
RFC7239“转发标头”定义了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框架将提供ForwardedHeaderFilter。通过将设置server.forward-headers-strategy
为,可以将其注册为应用程序中的Servlet过滤器FRAMEWORK
。
如果您的应用程序在Cloud Foundry或Heroku中运行,则该server.forward-headers-strategy 属性默认为NATIVE 。在所有其他情况下,它默认为NONE 。 |
|
---|---|
3.12.1. 自定义Tomcat的代理配置
如果使用Tomcat,则可以另外配置用于承载“转发的”信息的标头名称,如以下示例所示:
物产
Yaml
server.tomcat.remoteip.remote-ip-header=x-your-remote-ip-header
server.tomcat.remoteip.protocol-header=x-your-protocol-header
Tomcat还配置有一个默认正则表达式,该正则表达式与要信任的内部代理匹配。默认情况下,IP地址10/8
,192.168/16
,169.254/16
并且127/8
是值得信赖的。您可以通过在上添加一个条目来自定义阀门的配置application.properties
,如以下示例所示:
物产
Yaml
server.tomcat.remoteip.internal-proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3}
您可以通过将设置internal-proxies 为空来信任所有代理(但在生产环境中不要这样做)。 |
|
---|---|
您可以RemoteIpValve
通过关闭自动开关(设置为set server.forward-headers-strategy=NONE
)并在TomcatServletWebServerFactory
bean中添加新的Valve实例来完全控制Tomcat的配置。
3.13. 使用Tomcat启用多个连接器
您可以在中添加,org.apache.catalina.connector.Connector
以TomcatServletWebServerFactory
允许多个连接器,包括HTTP和HTTPS连接器,如以下示例所示:
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addAdditionalTomcatConnectors(createSslConnector());
return tomcat;
}
private Connector createSslConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
try {
File keystore = new ClassPathResource("keystore").getFile();
File truststore = new ClassPathResource("keystore").getFile();
connector.setScheme("https");
connector.setSecure(true);
connector.setPort(8443);
protocol.setSSLEnabled(true);
protocol.setKeystoreFile(keystore.getAbsolutePath());
protocol.setKeystorePass("changeit");
protocol.setTruststoreFile(truststore.getAbsolutePath());
protocol.setTruststorePass("changeit");
protocol.setKeyAlias("apitester");
return connector;
}
catch (IOException ex) {
throw new IllegalStateException("can't access keystore: [" + keystore
+ "] or truststore: [" + truststore + "]", ex);
}
}
3.14. 使用Tomcat的LegacyCookieProcessor
默认情况下,Spring Boot使用的嵌入式Tomcat不支持Cookie格式的“版本0”,因此您可能会看到以下错误:
java.lang.IllegalArgumentException:Cookie值中存在无效字符[32]
如果可能的话,您应该考虑将代码更新为仅存储符合以后Cookie规范的值。但是,如果无法更改cookie的编写方式,则可以将Tomcat配置为使用LegacyCookieProcessor
。要切换到LegacyCookieProcessor
,请使用WebServerFactoryCustomizer
添加了的Bean TomcatContextCustomizer
,如以下示例所示:
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
return (factory) -> factory
.addContextCustomizers((context) -> context.setCookieProcessor(new LegacyCookieProcessor()));
}
3.15. 启用Tomcat的MBean注册表
默认情况下,嵌入式Tomcat的MBean注册表是禁用的。这样可以最大程度地减少Tomcat的内存占用。例如,如果要使用Tomcat的MBean,以便可以将它们用于通过Micrometer公开指标,则必须使用该server.tomcat.mbeanregistry.enabled
属性,如以下示例所示:
物产
Yaml
server.tomcat.mbeanregistry.enabled=true
3.16. 使用Undertow启用多个侦听器
向中添加一个UndertowBuilderCustomizer
,UndertowServletWebServerFactory
并向中添加一个侦听器Builder
,如以下示例所示:
@Bean
public UndertowServletWebServerFactory servletWebServerFactory() {
UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
@Override
public void customize(Builder builder) {
builder.addHttpListener(8080, "0.0.0.0");
}
});
return factory;
}
3.17. 使用@ServerEndpoint创建WebSocket端点
如果要在使用@ServerEndpoint
嵌入式容器的Spring Boot应用程序中使用,必须声明一个single ServerEndpointExporter
@Bean
,如以下示例所示:
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
前面示例中显示的bean将所有带@ServerEndpoint
注释的bean注册到基础WebSocket容器中。当部署到独立的servlet容器时,此角色由servlet容器初始化程序执行,并且ServerEndpointExporter
不需要bean。