嵌入式Web服务器
每个Spring Boot Web应用程序都包含一个嵌入式Web服务器。此功能会导致许多操作方法问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器。本节回答了这些问题。摘译自官方文档
使用其他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并为Spring MVC包含Jetty:
<properties>
<servlet-api.version> 3.1.0 <
/servlet-api.version> </ properties>
<dependency>
<groupId> org.springframework.boot </ groupId>
<artifactId> spring-boot-starter-web </ artifactId>
<exclusions>
<! - 排除Tomcat依赖项 - >
<exclusion>
<groupId> org.springframework.boot </ groupId>
<artifactId> spring-boot-starter-tomcat </ artifactId>
</ exclusion >
</ exclusions>
</ dependency>
<! - 使用Jetty - >
<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示例显示如何排除Netty并包含Spring WebFlux的Undertow:
configurations {
// exclude Reactor Netty
compile.exclude module: 'spring-boot-starter-reactor-netty'
}
dependencies {
compile 'org.springframework.boot:spring-boot-starter-webflux'
// Use Undertow instead
compile 'org.springframework.boot:spring-boot-starter-undertow'
// ...
}
|
禁用Web服务器
如果您的类路径包含启动Web服务器所需的位,Spring Boot将自动启动它。要禁用此行为,请WebApplicationType
在您的配置中进行配置application.properties
,如以下示例所示:
<span style="color:#333333"><span style="color:#000000"><span style="color:#7f007f">spring.main.web-application-type</span> = none</span></span>
更改HTTP端口
在独立应用程序中,主HTTP端口默认为8080
但可以设置 server.port
(例如,application.properties
作为System属性或作为System属性)。由于轻松绑定Environment
值,您还可以使用SERVER_PORT
(例如,作为OS环境变量)。
要完全关闭HTTP端点但仍然创建一个WebApplicationContext
,请使用server.port=-1
。(这样做有时对测试很有用。)
有关更多详细信息,请参阅“ Spring Boot功能”部分中的“ 第28.4.4节 ” ,“自定义嵌入式Servlet容器”或ServerProperties
源代码。
使用随机未分配的HTTP端口
要扫描一个空闲端口(使用OS本机来防止冲突),请使用server.port=0
。
在运行时发现HTTP端口
您可以从日志输出或ServletWebServerApplicationContext
通过其输出访问服务器正在运行的端口WebServer
。获得该功能并确保已初始化的最佳方法是添加一个@Bean
类型,ApplicationListener<ServletWebServerInitializedEvent>
并在发布时将容器拉出事件。
使用的测试@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
还可以使用@LocalServerPort
注释将实际端口注入字段,如以下示例所示:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class MyWebIntegrationTests {
@Autowired
ServletWebServerApplicationContext server;
@LocalServerPort
int port;
// ...
}
|
启用HTTP响应压缩
Jetty,Tomcat和Undertow支持HTTP响应压缩。它可以启用application.properties
,如下所示:
<span style="color:#333333"><span style="color:#000000"><span style="color:#7f007f">server.compression.enabled</span> = true</span></span>
默认情况下,响应必须至少为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
属性来配置此行为。
配置SSL
可以通过设置各种server.ssl.*
属性以声明方式配置SSL ,通常在application.properties
或中application.yml
。以下示例显示了在以下位置设置SSL属性application.properties
:
<span style="color:#333333"><span style="color:#000000"><span style="color:#7f007f">server.port</span> = 8443
<span style="color:#7f007f">server.ssl.key-store</span> = classpath:keystore.jks
<span style="color:#7f007f">server.ssl.key-store-password</span> = secret
<span style="color:#7f007f">server.ssl.key-password</span> = another-secret</span></span>
有关Ssl
所有支持的属性的详细信息,请参阅。
使用上述示例之类的配置意味着应用程序不再支持端口8080上的普通HTTP连接器.Spring Boot不支持HTTP连接器和HTTPS连接器的配置application.properties
。如果要同时使用这两者,则需要以编程方式配置其中一个。我们建议使用 application.properties
配置HTTPS,因为HTTP连接器更容易以编程方式配置。有关spring-boot-sample-tomcat-multi-connectors
示例,请参阅 示例项目。
配置HTTP / 2
您可以使用server.http2.enabled
配置属性在Spring Boot应用程序中启用HTTP / 2支持 。此支持取决于所选的Web服务器和应用程序环境,因为JDK8不支持该协议。
Spring Boot不支持 |
带有Undertow的HTTP / 2
从Undertow 1.4.0+开始,支持HTTP / 2,对JDK8没有任何额外要求。
带Jetty的HTTP / 2
从Jetty 9.4.8开始,Conscrypt库也支持HTTP / 2 。要启用该支持,您的应用程序需要有两个额外的依赖项:org.eclipse.jetty:jetty-alpn-conscrypt-server
和org.eclipse.jetty.http2:http2-server
。
使用Tomcat的HTTP / 2
Spring Boot默认使用Tomcat 9.0.x,它在使用JDK 9或更高版本时支持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会记录以下错误:
ERROR 8787 --- [ main] o.a.coyote.http11.Http11NioProtocol : The upgrade handler [org.apache.coyote.http2.Http2Protocol] for [h2] only supports upgrade via ALPN but has been configured for the ["https-jsse-nio-8443"] connector that does not support ALPN.
此错误不是致命的,应用程序仍然以HTTP / 1.1 SSL支持启动。
带有Reactor Netty的HTTP / 2
在spring-boot-webflux-starter
默认情况下,反应堆的Netty作为服务器使用。可以使用JDK 9或更高版本的JDK支持为Reactor Netty配置HTTP / 2。对于JDK 8环境或最佳运行时性能,此服务器还支持具有本机库的HTTP / 2。要启用它,您的应用程序需要具有其他依赖项。
Spring Boot管理io.netty:netty-tcnative-boringssl-static
“超级jar” 的版本 ,包含所有平台的本机库。开发人员可以选择使用分类器仅导入所需的依赖项(请参阅Netty官方文档)。
配置Web服务器
通常,您应首先考虑使用众多可用配置键中的一个,并通过在您的application.properties
(application.yml
或环境等)中添加新条目来自定义您的Web服务器,请参阅“ 第77.8节”,“发现外部属性的内置选项” “) 。该server.*
命名空间是非常有用的在这里,它包括命名空间一样server.tomcat.*
,server.jetty.*
和其他人,了解特定服务器的功能。请参阅附录A,常见应用程序属性列表。
前面的部分涵盖了许多常见用例,例如压缩,SSL或HTTP / 2。但是,如果您的用例不存在配置密钥,则应该查看 WebServerFactoryCustomizer
。您可以声明这样的组件并获得与您选择的服务器工厂相关的访问权限:您应该为所选服务器(Tomcat,Jetty,Reactor Netty,Undertow)和所选Web堆栈(Servlet或Reactive)选择变体。
以下示例适用于具有spring-boot-starter-web
(Servlet堆栈)的Tomcat :
@Component
public class MyTomcatWebServerCustomizer
implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
// customize the factory here
}
}
另外Spring Boot提供:
服务器 | Servlet堆栈 | 反应堆栈 |
---|---|---|
Tomcat的 |
|
|
码头 |
|
|
暗潮 |
|
|
反应堆 |
N / A |
|
一旦您有权访问a WebServerFactory
,您通常可以向其添加定制器以配置特定部件,例如连接器,服务器资源或服务器本身 - 所有这些都使用特定于服务器的API。
作为最后的手段,您还可以声明自己的WebServerFactory
组件,它将覆盖Spring Boot提供的组件。在这种情况下,您不能再依赖server
命名空间中的配置属性。
向应用程序添加Servlet,过滤器或监听器
在servlet堆栈应用程序中,即使用spring-boot-starter-web
,有两种方法可以向应用程序添加Servlet
,Filter
和ServletContextListener
,以及Servlet API支持的其他侦听器:
使用Spring Bean添加Servlet,过滤器或监听器
要添加Servlet
,Filter
或servlet *Listener
使用的Spring bean,你必须提供一个@Bean
它的定义。当您想要注入配置或依赖项时,这样做非常有用。但是,您必须非常小心,它们不会导致太多其他bean的初始化,因为它们必须在应用程序生命周期的早期安装在容器中。(例如,让它们依赖于您的DataSource
或JPA配置并不是一个好主意。)您可以通过在首次使用而不是初始化时懒惰地初始化bean来解决此类限制。
在的情况下Filters
和Servlets
,还可以通过添加添加映射和初始化参数FilterRegistrationBean
或ServletRegistrationBean
代替或除了下面的部件。
如果 |
像任何其他Spring bean一样,您可以定义Servlet过滤器bean的顺序; 请务必检查“ 名为”将Servlet,过滤器和监听器注册为Spring Beans “部分。
禁用Servlet或过滤器的注册
正如前面所述,任何 Servlet
或Filter
豆与servlet容器自动注册。要禁用特定Filter
或Servlet
bean的注册,请为其创建注册Bean并将其标记为已禁用,如以下示例所示:
@Bean
public FilterRegistrationBean registration(MyFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
使用类路径扫描添加Servlet,过滤器和监听器
@WebServlet
,@WebFilter
和带@WebListener
注释的类可以通过使用@Configuration
带有@ServletComponentScan
并指定包含要注册的组件的包的类来注释类来自动注册嵌入式servlet容器。默认情况下,@ServletComponentScan
从带注释的类的包中进行扫描。
配置访问日志记录
可以通过各自的命名空间为Tomcat,Undertow和Jetty配置访问日志。
例如,以下设置使用自定义模式在Tomcat上记录访问权限 。
server.tomcat.basedir=my-tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
日志的默认位置是 |
可以以类似的方式配置Undertow的访问日志记录,如以下示例所示:
server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=%t %a "%r" %s (%D ms)
日志存储在logs
相对于应用程序工作目录的目录中。您可以通过设置server.undertow.accesslog.directory
属性来自定义此位置 。
最后,Jetty的访问日志记录也可以配置如下:
server.jetty.accesslog.enabled=true
server.jetty.accesslog.filename=/var/log/jetty-access.log
默认情况下,日志会重定向到System.err
。有关更多详细信息,请参阅 Jetty文档。
在前端代理服务器后面运行
您的应用程序可能需要发送302
重定向或使用绝对链接将内容呈现回自身。在代理后面运行时,调用者需要指向代理的链接,而不是托管应用程序的计算机的物理地址。通常,这种情况是通过与代理的合同来处理的,代理会添加标题以告诉后端如何构建自身链接。
如果代理添加了常规X-Forwarded-For
和X-Forwarded-Proto
头文件(大多数代理服务器都这样做),则应该正确呈现绝对链接,前提 server.use-forward-headers
是true
在您的中设置application.properties
。
如果您的应用程序在Cloud Foundry或Heroku中运行,则该 |
自定义Tomcat的代理配置
如果使用Tomcat,还可以配置用于携带“转发”信息的标头名称,如以下示例所示:
server.tomcat.remote-ip-header=x-your-remote-ip-header
server.tomcat.protocol-header=x-your-protocol-header
Tomcat还配置了一个默认正则表达式,该表达式匹配要信任的内部代理。默认情况下,IP地址中10/8
,192.168/16
, 169.254/16
和127/8
是值得信赖的。您可以通过添加条目来自定义阀门的配置application.properties
,如以下示例所示:
server.tomcat.internal-proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3}
仅当使用属性文件进行配置时才需要双反斜杠。如果使用YAML,则单个反斜杠就足够了,并且值等于前面示例中显示的值 |
您可以通过将其设置 |
您可以RemoteIpValve
通过关闭自动关闭(为此,设置server.use-forward-headers=false
)并在TomcatServletWebServerFactory
bean中添加新的阀门实例来完全控制Tomcat的配置。
使用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: [" + "keystore" + "]", ex);
}
}
使用Tomcat的LegacyCookieProcessor
默认情况下,Spring Boot使用的嵌入式Tomcat不支持Cookie格式的“Version 0”,因此您可能会看到以下错误:
java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value
如果可能的话,您应该考虑将代码更新为仅存储符合以后Cookie规范的值。但是,如果您无法更改cookie的编写方式,则可以将Tomcat配置为使用 LegacyCookieProcessor
。要切换到LegacyCookieProcessor
,请使用WebServerFactoryCustomizer
添加a 的 bean TomcatContextCustomizer
,如以下示例所示:
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
return (factory) -> factory.addContextCustomizers(
(context) -> context.setCookieProcessor(new LegacyCookieProcessor()));
}
使用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;
}
使用@ServerEndpoint创建WebSocket端点
如果要在使用@ServerEndpoint
嵌入式容器的Spring Boot应用程序中使用,则必须声明一个ServerEndpointExporter
@Bean
,如以下示例所示:
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
前面示例中显示的@ServerEndpoint
bean使用基础WebSocket容器注册任何带注释的bean。当部署到独立的servlet容器时,此角色由servlet容器初始化程序执行,并且ServerEndpointExporter
不需要该 bean。