- 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.propertiesSystem属性中或作为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。最好的方法是确保它已被初始化,是添加一个@BeantypeApplicationListener<WebServerInitializedEvent>并在事件发布时将其从事件中拉出。
使用的测试@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)还可以通过使用@LocalServerPort批注将实际端口注入字段中,如以下示例所示:
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)public class MyWebIntegrationTests {@LocalServerPortint 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/htmltext/xmltext/plaintext/csstext/javascriptapplication/javascriptapplication/jsonapplication/xml
您可以通过设置server.compression.mime-types属性来配置此行为。
3.7. 配置SSL
可以通过设置各种server.ssl.*属性来声明性地配置SSL ,通常在application.properties或中application.yml。以下示例显示了在中设置SSL属性application.properties:
物产
Yaml
server.port=8443server.ssl.key-store=classpath:keystore.jksserver.ssl.key-store-password=secretserver.ssl.key-password=another-secret
有关Ssl所有受支持属性的详细信息,请参见。
使用上述示例的配置意味着应用程序不再在端口8080上支持纯HTTP连接器。SpringBoot不支持通过进行HTTP连接器和HTTPS连接器的配置application.properties。如果要同时拥有两者,则需要以编程方式配置它们之一。我们建议您使用application.propertiesHTTPS进行配置,因为HTTP连接器是两者中以编程方式配置的比较容易的方法。
3.8. 配置HTTP / 2
您可以使用server.http2.enabled配置属性在Spring Boot应用程序中启用HTTP / 2支持。该支持取决于所选的Web服务器和应用程序环境,因为并非所有JDK8版本都立即支持该协议。
Spring Boot不建议使用h2cHTTP / 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,我们需要向现有连接器添加连接工厂:@Beanpublic TomcatConnectorCustomizer connectorCustomizer() {return (connector) -> connector.addUpgradeProtocol(new Http2Protocol());}
对于Netty,我们需要添加@Beanpublic 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选项:@Beanpublic NettyServerCustomizer serverCustomizer() {return (server) -> server.protocol(HttpProtocol.H2C);}
@Beanpublic 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还提供:@Componentpublic class MyTomcatWebServerCustomizerimplements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {@Overridepublic 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或Servletbean的注册,请为其创建注册bean并将其标记为已禁用,如以下示例所示:
@Beanpublic 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-tomcatserver.tomcat.accesslog.enabled=trueserver.tomcat.accesslog.pattern=%t %a %r %s (%D ms)
日志的默认位置是logs相对于Tomcat基本目录的目录。默认情况下,该logs目录是一个临时目录,因此您可能需要修复Tomcat的基本目录或为日志使用绝对路径。在前面的示例中,日志my-tomcat/logs相对于应用程序的工作目录可用。 |
|
|---|---|
可以用类似的方式配置Undertow的访问日志,如以下示例所示:
物产
Yaml
server.undertow.accesslog.enabled=trueserver.undertow.accesslog.pattern=%t %a %r %s (%D ms)
日志存储在logs相对于应用程序工作目录的目录中。您可以通过设置server.undertow.accesslog.dir属性来自定义此位置。
最后,Jetty的访问日志也可以配置如下:
物产
Yaml
server.jetty.accesslog.enabled=trueserver.jetty.accesslog.filename=/var/log/jetty-access.log
默认情况下,日志重定向到System.err。有关更多详细信息,请参见Jetty文档。
3.12. 在前端代理服务器后面运行
如果您的应用程序是在代理,负载均衡器之后或在云中运行的,则请求信息(例如主机,端口,方案等)可能会随之变化。您的应用程序可能正在运行10.10.10.10:8080,但是HTTP客户端只能看到example.org。
RFC7239“转发标头”定义了ForwardedHTTP标头;代理可以使用此标头来提供有关原始请求的信息。您可以将应用程序配置为读取这些标头,并在创建链接并将其发送到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-headerserver.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)并在TomcatServletWebServerFactorybean中添加新的Valve实例来完全控制Tomcat的配置。
3.13. 使用Tomcat启用多个连接器
您可以在中添加,org.apache.catalina.connector.Connector以TomcatServletWebServerFactory允许多个连接器,包括HTTP和HTTPS连接器,如以下示例所示:
@Beanpublic 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,如以下示例所示:
@Beanpublic 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,如以下示例所示:
@Beanpublic UndertowServletWebServerFactory servletWebServerFactory() {UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {@Overridepublic void customize(Builder builder) {builder.addHttpListener(8080, "0.0.0.0");}});return factory;}
3.17. 使用@ServerEndpoint创建WebSocket端点
如果要在使用@ServerEndpoint嵌入式容器的Spring Boot应用程序中使用,必须声明一个single ServerEndpointExporter @Bean,如以下示例所示:
@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
前面示例中显示的bean将所有带@ServerEndpoint注释的bean注册到基础WebSocket容器中。当部署到独立的servlet容器时,此角色由servlet容器初始化程序执行,并且ServerEndpointExporter不需要bean。
