Servlet Web Applications

如果要构建基于 servlet 的 Web 应用程序,则可以利用 Spring Boot 对 Spring MVC 或 Jersey 的自动配置功能。

The “Spring Web MVC Framework”

{url-spring-framework-docs}/web/webmvc.html[Spring Web MVC 框架](通常称为 “Spring MVC”)是一个丰富的 "`model view controller`"Web 框架。Spring MVC 允许你创建特殊的 `@Controller`或 `@RestController`bean 来处理传入的 HTTP 请求。控制器中的方法通过使用 `@RequestMapping`注释映射到 HTTP。

以下代码显示了一个提供 JSON 数据的典型 @RestController

“WebMvc.fn”,函数变量将路由配置从请求的实际处理中分离,如下例所示:

Spring MVC 是核心 Spring 框架的一部分,详细信息可以在 {url-spring-framework-docs}/web/webmvc.html[参考文档]中找到。另外,还有几个指南涵盖 Spring MVC,可在 [role="bare"][role="bare"]https://spring.io/guides中找到。

你可以根据需要定义任意数量的 `RouterFunction`bean 来模块化路由器的定义。如果需要应用优先级,可以对 bean 进行排序。

Spring MVC Auto-configuration

Spring Boot 为 Spring MVC 提供的自动配置适用于大多数应用程序。它取代了 `@EnableWebMvc`的需求,两者不能一起使用。除了 Spring MVC 的默认值之外,自动配置还提供以下功能:

  • 包含 `ContentNegotiatingViewResolver`和 `BeanNameViewResolver`bean。

  • 支持提供静态资源,包括对 WebJar 的支持(later in this document 中已介绍)。

  • 自动注册 ConverterGenericConverterFormatter bean。

  • 支持 HttpMessageConverterslater in this document 中已介绍)。

  • 自动注册 MessageCodesResolverlater in this document 中已介绍)。

  • Static index.html support.

  • 自动使用 ConfigurableWebBindingInitializer bean(later in this document 中已介绍)。

如果您希望保留这些 Spring Boot MVC 自定义,并进行更多 {url-spring-framework-docs}/web/webmvc.html[MVC 自定义](拦截器、格式化程序、视图控制器以及其他功能),则可以添加自己的 @Configuration 类,类型为 WebMvcConfigurer,但 without @EnableWebMvc

如果您希望提供 RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver 的自定义实例,但仍保留 Spring Boot MVC 自定义,则可以声明一个 WebMvcRegistrations 类型的 bean,并使用它来提供这些组件的自定义实例。这些自定义实例将受到 Spring MVC 的进一步初始化和配置。为了参与,并且在需要时覆盖后续处理过程,应该使用 WebMvcConfigurer

如果您不想使用自动配置,并且希望完全控制 Spring MVC,请添加您自己的 @Configuration,其中带 @EnableWebMvc 注释。或者,按照 @EnableWebMvc 的 Javadoc 中所述,添加自己的 @Configuration 注释的 DelegatingWebMvcConfiguration

Spring MVC Conversion Service

Spring MVC 使用的 ConversionService 与从 application.propertiesapplication.yaml 文件转换值所使用的 ConversionService 不同。这意味着 PeriodDurationDataSize 转换器不可用,并且 @DurationUnit@DataSizeUnit 注释将被忽略。

如果您希望自定义 Spring MVC 所使用的 ConversionService,则可以提供一个包含 addFormatters 方法的 WebMvcConfigurer bean。您可以通过此方法注册您喜欢使用的任何转换器,或者可以委托 ApplicationConversionService 上提供的静态方法。

还可以使用 spring.mvc.format.* 配置属性自定义转换。未配置时会使用以下默认值:

Property DateTimeFormatter

configprop:spring.mvc.format.date[]

ofLocalizedDate(FormatStyle.SHORT)

configprop:spring.mvc.format.time[]

ofLocalizedTime(FormatStyle.SHORT)

configprop:spring.mvc.format.date-time[]

ofLocalizedDateTime(FormatStyle.SHORT)

HttpMessageConverters

Spring MVC 使用 HttpMessageConverter 接口转换 HTTP 请求和响应。默认情况下会包含明智的默认值。例如,可以自动将对象转换为 JSON(使用 Jackson 库)或 XML(如果可用,请使用 Jackson XML 扩展,如果 Jackson XML 扩展不可用,则使用 JAXB)。默认情况下,字符串会以 UTF-8 进行编码。

如果您需要添加或自定义转换器,则可以使用 Spring Boot 的 HttpMessageConverters 类,如下面的清单所示:

上下文中的所有 HttpMessageConverter bean 都被添加到转换器列表中。你还可以通过相同的方式覆盖默认转换器。

MessageCodesResolver

Spring MVC 有一个生成错误代码的策略,用于根据绑定错误呈现错误消息:MessageCodesResolver。如果你设置了 configprop:spring.mvc.message-codes-resolver-format[] 属性 PREFIX_ERROR_CODEPOSTFIX_ERROR_CODE,Spring Boot 会为你创建一个(请参见枚举: {url-spring-framework-javadoc}/org/springframework/validation/DefaultMessageCodesResolver.Format.html[DefaultMessageCodesResolver.Format])。

Static Content

默认情况下,Spring Boot 从类路径的 /static 目录(或 /public/resources/META-INF/resources)或 ServletContext 的根目录提供静态内容。它使用 Spring MVC 的 ResourceHttpRequestHandler,以便你可以通过添加自己的 WebMvcConfigurer 并覆盖 addResourceHandlers 方法来修改该行为。

在独立网络应用程序中,来自容器的默认 servlet 没有启用。可以使用 configprop:server.servlet.register-default-servlet[] 属性启用它。

默认 servlet 作为备用,如果 Spring 决定不处理 ServletContext 中根目录的内容,则它会处理这些内容。这是不常发生的(除非你修改了默认 MVC 配置),因为 Spring 始终可以通过 DispatcherServlet 处理请求。

默认情况下,按以下方式映射 /, but you can tune that with the configprop:spring.mvc.static-path-pattern[] property. For instance, relocating all resources to /resources/ 上的资源:

spring:
  mvc:
    static-path-pattern: "/resources/**"

您还可以使用 configprop:spring.web.resources.static-locations[] 属性自定义静态资源位置(用目录位置列表替换默认值)。根 Servlet 上下文路径 "/" 也自动添加为一个位置。

除先前提到的 “standard” 静态资源位置外,还对 Webjars content 做了一个特殊情况。默认情况下,/webjars/** 中路径的任何资源都在打包成 Webjars 格式时从 JAR 文件中提供。该路径可以 configprop:spring.mvc.webjars-path-pattern[] 属性进行自定义。

如果您的应用程序打包成 JAR,请不要使用 src/main/webapp 目录。尽管此目录是一个通用标准,但它与战时包装配合使用时可以 only,并且如果您生成 JAR,大多数构建工具会默默忽略它。

Spring Boot 还支持 Spring MVC 提供的高级资源处理功能,允许使用案例,例如缓存破坏静态资源或使用与版本无关的 URL 进行 Webjars。

若要使用与版本无关的 Webjars URL,请添加 webjars-locator-core 依赖项。然后声明您的 Webjar。以 jQuery 为例,添加 "/webjars/jquery/jquery.min.js" 会生成 "/webjars/jquery/x.y.z/jquery.min.js",其中 x.y.z 是 Webjar 版本。

如果您使用 JBoss,则需要声明 webjars-locator-jboss-vfs 依赖项,而不是 webjars-locator-core。否则,所有 Webjars 会解析为 404

若要使用缓存破坏,以下配置为所有静态资源配置了一个缓存破坏解决方案,有效地在 URL 中添加了一个内容散列值,例如 <link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>

spring:
  web:
    resources:
      chain:
        strategy:
          content:
            enabled: true
            paths: "/**"

由于为 Thymeleaf 和 FreeMarker 自动配置了 ResourceUrlEncodingFilter,因此运行时在模板中重写了对资源的链接。在使用 JSP 时,您应手动声明此过滤器。其他模板引擎目前未自动支持,但可以使用自定义模板宏/帮助器和 {url-spring-framework-javadoc}/org/springframework/web/servlet/resource/ResourceUrlProvider.html[ResourceUrlProvider]。

例如,通过 JavaScript 模块加载器动态加载资源时,重命名文件不是一个选择。因此,也支持并可以结合其他策略。如以下示例所示,“固定”策略在不更改文件名的情况下在 URL 中添加一个静态版本字符串:

spring:
  web:
    resources:
      chain:
        strategy:
          content:
            enabled: true
            paths: "/**"
          fixed:
            enabled: true
            paths: "/js/lib/"
            version: "v12"

通过此配置,位于 "/js/lib/" 下的 JavaScript 模块使用固定版本策略 ("/v12/js/lib/mymodule.js"),而其他资源仍使用内容版本策略 (<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>)。

请参阅 {code-spring-boot-autoconfigure-src}/web/WebProperties.java[WebProperties.Resources] 以了解更多受支持的选项。

此功能已在一个专用的 blog post 和 Spring Framework 的 {url-spring-framework-docs}/web/webmvc/mvc-config/static-resources.html[参考文档] 中得到彻底说明。

Welcome Page

Spring Boot 支持静态欢迎页面和模板化欢迎页面。它首先在配置的静态内容位置中查找一个 index.html 文件。如果没有找到,它会查找一个 index 模板。如果找到任一个,则它会自动用作应用程序的欢迎页面。

这只是一个适用于应用程序定义的实际索引路由的回退。排序是由 HandlerMapping bean 的顺序定义的,默认情况下如下:

RouterFunctionMapping

使用 RouterFunction bean 声明的端点

RequestMappingHandlerMapping

@Controller bean 中声明的端点

WelcomePageHandlerMapping

The welcome page support

Custom Favicon

与其他静态资源一样,Spring Boot 在配置的静态内容位置中检查 favicon.ico。如果存在这样的文件,则自动用作应用程序的 favicon。

Path Matching and Content Negotiation

Spring MVC 可以通过查看请求路径并将其与应用程序中定义的映射匹配来将传入的 HTTP 请求映射到处理程序(例如,Controller 方法上的 @GetMapping 注释)。

Spring Boot 默认情况下选择禁用后缀模式匹配,这意味着像 "GET /projects/spring-boot.json" 这样的请求将不会匹配到 @GetMapping("/projects/spring-boot") 映射。这被认为是 Spring MVC 应用程序的最佳实践。此功能过去主要用于不发送适当“Accept”请求标头的 HTTP 客户端;我们需要确保向客户端发送正确的 Content Type。如今,内容协商可靠得多。

还有其他方法可以处理始终发送适当的“Accept”请求标头的问题。我们可以使用查询参数,确保像 "GET /projects/spring-boot?format=json" 这样的请求将映射到 @GetMapping("/projects/spring-boot"),而不是使用后缀匹配:

spring:
  mvc:
    contentnegotiation:
      favor-parameter: true

或者如果你希望使用不同的参数名称:

spring:
  mvc:
    contentnegotiation:
      favor-parameter: true
      parameter-name: "myparam"

大多数标准媒体类型都开箱即用,但你也可以定义新的媒体类型:

spring:
  mvc:
    contentnegotiation:
      media-types:
        markdown: "text/markdown"

从 Spring Framework 5.3 开始,Spring MVC 支持使用两种策略将请求路径匹配到控制器。默认情况下,Spring Boot 使用 PathPatternParser 策略。PathPatternParser 是一种 optimized implementation,但与 AntPathMatcher 策略相比有一定限制。PathPatternParser 限制了 {url-spring-framework-docs}/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates[某些路径模式变体]。它也不兼容将 DispatcherServlet 配置有路径前缀(configprop:spring.mvc.servlet.path[])。

可以使用 configprop:spring.mvc.pathmatch.matching-strategy[] 配置属性对该策略进行配置,如下例所示:

spring:
  mvc:
    pathmatch:
      matching-strategy: "ant-path-matcher"

默认情况下,如果为请求找不到处理程序,Spring MVC 将发送 404 Not Found 错误响应。要改为抛出 NoHandlerFoundException,将 configprop:spring.mvc.throw-exception-if-no-handler-found 设置为 true。请注意,默认情况下,serving of static content 映射到 / and will, therefore, provide a handler for all requests. For a NoHandlerFoundException to be thrown, you must also set configprop:spring.mvc.static-path-pattern[] to a more specific value such as /resources/,或者将 configprop:spring.web.resources.add-mappings[] 设置为 false 以完全禁用提供静态内容。

ConfigurableWebBindingInitializer

Spring MVC 使用 WebBindingInitializer 为特定请求初始化 WebDataBinder。如果你创建了自己的 ConfigurableWebBindingInitializer @Bean,Spring Boot 会自动配置 Spring MVC 以使用它。

Template Engines

除了 REST Web 服务,你还可以使用 Spring MVC 来提供动态 HTML 内容。Spring MVC 支持各种模板技术,包括 Thymeleaf、FreeMarker 和 JSP。此外,许多其他模版引擎还包括自己的 Spring MVC 集成。

Spring Boot 包含以下模板引擎的自动配置支持:

如果可能,应避免使用 JSP。在内嵌 Servlet 容器中使用它们时,会有一些 known limitations

当使用默认配置将其中一个模板引擎与之一起使用时,会从 src/main/resources/templates 中自动获取模板。

应用程序的运行方式不同,IDE 对类路径的排序方式也不同。从主方法在 IDE 中运行应用程序,其排序方式与使用 Maven 或 Gradle 或从已打包 jar 中运行应用程序的排序方式不同。这可能会导致 Spring Boot 无法找到预期的模板。如果你遇到此问题,则可以重新排序 IDE 中的类路径,以首先放置模块的类和资源。

Error Handling

Spring Boot 默认情况下,提供一个以合理的方式处理所有错误的 /error 映射,并且在 Servlet 容器中注册为 “global” 错误页面。对于机器客户端,它会生成一个 JSON 响应,其中包含错误详细信息、HTTP 状态和异常消息。对于浏览器客户端,有一个 “whitelabel” 错误视图,以 HTML 格式呈现相同的数据(要自定义它,请添加一个解析到 errorView)。

如果你希望自定义默认的错误处理行为,可以设置许多 server.error 属性。请参阅附录的 “Server Properties” 部分。

要完全替换默认行为,可以实现 ErrorController,并注册该类型的 bean 定义,或者添加类型为 ErrorAttributes 的 bean,以使用现有机制,但替换其内容。

BasicErrorController 可以用作自定义 ErrorController 的基类。如果你要为新内容类型添加一个处理程序,这尤其有用(默认情况下专门处理 text/html,并为其他所有内容提供后备)。为此,请扩展 BasicErrorController,添加一个公用方法 @RequestMapping,该方法具有 produces 属性,并创建新类型的 bean。

从 Spring Framework 6.0 开始,支持 {url-spring-framework-docs}/web/webmvc/mvc-ann-rest-exceptions.html[RFC 7807 问题详细信息]。Spring MVC 可以生成带有 application/problem+json 媒体类型自定义错误消息,例如:

{
	"type": "https://example.org/problems/unknown-project",
	"title": "Unknown project",
	"status": 404,
	"detail": "No project found for id 'spring-unknown'",
	"instance": "/projects/spring-unknown"
}

可以通过将 configprop:spring.mvc.problemdetails.enabled[] 设置为 true 来启用此支持。

你还可以定义使用 `@ControllerAdvice`注释的类,以自定义对于特定控制器和/或异常类型返回的 JSON 文档,如下例所示:

在前面的示例中,如果 MyException 由与 SomeController 相同包中定义的控制器抛出,则使用 MyErrorBody POJO 的 JSON 表示形式,而不是 ErrorAttributes 表示形式。

在某些情况下,在控制器级别处理的错误并未由 Web 观察或 metrics infrastructure 记录。应用程序可以通过 {url-spring-framework-docs}/integration/observability.html#observability.http-server.servlet[在观察上下文上设置处理的异常] 来确保用观察记录此类异常。

Custom Error Pages

如果要为给定状态代码显示自定义 HTML 错误页面,可以在 /error 目录中添加文件。错误页面可以是静态 HTML(也就是说,在任意静态资源目录中添加),也可以使用模板构建。文件名称应该为确切的状态代码或序列掩码。

例如,要将 404 映射到静态 HTML 文件,你的目录结构如下:

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- public/
             +- error/
             |   +- 404.html
             +- <other public assets>

要使用 FreeMarker 模板映射所有 5xx 错误,你的目录结构如下:

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- templates/
             +- error/
             |   +- 5xx.ftlh
             +- <other templates>

对于更复杂的映射,你还可以添加实现 ErrorViewResolver 接口的 bean,如下例所示:

你还可以使用常规 Spring MVC 功能,如 {url-spring-framework-docs}/web/webmvc/mvc-servlet/exceptionhandlers.html[@ExceptionHandler 方法] 和 {url-spring-framework-docs}/web/webmvc/mvc-controller/ann-advice.html[@ControllerAdvice]。然后,ErrorController 将获取任何未处理的异常。

Mapping Error Pages Outside of Spring MVC

对于不使用 Spring MVC 的应用程序,你可以使用 ErrorPageRegistrar 接口来直接注册 ErrorPages. 此抽象直接处理底层嵌入式 servlet 容器,即使没有 Spring MVC DispatcherServlet 也可以处理。

如果你注册的 ErrorPage 的路径最终由 Filter 处理(这在一些非 Spring Web 框架中很常见,如 Jersey 和 Wicket),则必须明确地将 Filter 注册为 ERROR 调度程序,如下例所示:

注意,默认 FilterRegistrationBean 不包括 ERROR 调度程序类型。

Error Handling in a WAR Deployment

部署到 servlet 容器时,Spring Boot 会使用其错误页面过滤器将具有错误状态的请求转发到适当的错误页面。这是必需的,因为 servlet 规范未提供用于注册错误页面的 API。根据你将 war 文件部署到的容器和你应用程序使用的技术,可能需要一些额外的配置。

错误页面过滤器仅在响应尚未提交时才能将请求转发到正确的错误页面。默认情况下,WebSphere Application Server 8.0 及更高版本在 servlet 的 service 方法成功完成后提交响应。你应通过将 com.ibm.ws.webcontainer.invokeFlushAfterService 设置为 false,来禁用此行为。

CORS Support

Cross-origin resource sharing (CORS)是 W3C specification 实施的 most browsers,它让你能够灵活地指定允许哪些类型的跨域请求,而不是使用一些不那么安全且功能较弱的方法,如 IFRAME 或 JSONP。

从 4.2 版本开始,Spring MVC {url-spring-framework-docs}/web/webmvc-cors.html[支持 CORS]。在你的 Spring Boot 应用程序中使用 {url-spring-framework-docs}/web/webmvc-cors.html#mvc-cors-controller[Controller 方法 CORS 配置] 来使用带有 {url-spring-framework-javadoc}/org/springframework/web/bind/annotation/CrossOrigin.html[@CrossOrigin] 注释,无需任何特定配置。{url-spring-framework-docs}/web/webmvc-cors.html#mvc-cors-global[全局 CORS 配置] 可以通过注册带有自定义 addCorsMappings(CorsRegistry) 方法的 WebMvcConfigurer bean 来定义,如下例所示:

JAX-RS and Jersey

如果您更喜欢针对 REST 终结点使用 JAX-RS 编程模型,您可以使用一种可用的实现来代替 Spring MVC. JerseyApache CXF开箱即用非常出色。CXF 要求您在应用程序上下文中将 Servlet`或 `Filter`注册为 `@Bean。Jersey 拥有部分原生 Spring 支持,因此我们也为它提供了 Spring Boot 中的自动配置支持,以及一个 starter。

要开始使用 Jersey,请包含 `spring-boot-starter-jersey`作为依赖项,然后您需要一个类型为 `ResourceConfig`的 `@Bean`来注册所有终结点,如下例所示:

Jersey 对可执行存档的扫描支持はかなり限定。例如,在运行一个可执行 war 文件时,它不能扫描一个 fully executable jar file或 `WEB-INF/classes`中包的终结点。要避免这种限制,不应使用 `packages`方法,而应使用 `register`方法单独注册终结点,如下例所示:

对于更高级别的自定义,您还可以注册任意数量实现 `ResourceConfigCustomizer`的 bean。

所有已注册的终结点都应使用 HTTP 资源注释(@GET`等)加上 `@Components,如下例所示:

由于 Endpoint`是一个 Spring `@Component,它的生命周期由 Spring 管理,并且您可以使用 @Autowired`注释来注入依赖项,以及使用 `@Value`注释来注入外部配置。默认情况下,Jersey servlet 会被注册并映射到 `/*。您可以通过添加 `@ApplicationPath`到您的 `ResourceConfig`来更改映射。

默认情况下,Jersey 会被设置为 ServletRegistrationBean`类型为 `jerseyServletRegistration`的 `@Bean`中的一个 servlet。默认情况下,该 servlet 会被延迟初始化,但您可以通过设置 `spring.jersey.servlet.load-on-startup`来自定义该行为。您可以通过创建一个具有相同名称自己的 bean 来禁用或覆盖该 bean。您也可以通过设置 `spring.jersey.type=filter(在这种情况下,要替换或覆盖的 @Bean`是 `jerseyFilterRegistration)来使用 filter 而非 servlet。该 filter 具有一个 @Order,您可以使用 `spring.jersey.filter.order`设置该属性。在将 Jersey 用作 filter 时,必须有一个将处理 Jersey 无拦截的任何请求的 servlet。如果您的应用程序不包含这样的 servlet,您可能要通过将 configprop:server.servlet.register-default-servlet[] 设置为 `true`来启用默认 servlet。可以通过使用 `spring.jersey.init.*`来指定一个属性 map 为 servlet 和 filter 注册提供初始化参数。

Embedded Servlet Container Support

对于 servlet 应用程序,Spring Boot 包括对嵌入 TomcatJettyUndertow服务器的支持。大多数开发人员使用合适的 "`Starter`"来获取一个完全配置的实例。默认情况下,嵌入服务器监听端口 `8080`上的 HTTP 请求。

Servlets, Filters, and Listeners

在使用嵌入 servlet 容器时,您可以使用 Spring bean 或通过扫描 servlet 组件来注册 servlet、filter 和所有来自 servlet 规格的侦听器(例如 HttpSessionListener)。

Registering Servlets, Filters, and Listeners as Spring Beans

任何是 Spring bean 的 Servlet、`Filter`或 servlet `*Listener`实例都会在嵌入容器中注册。如果您希望在配置期间引用来自您的 `application.properties`中的值,这可以特别方便。

默认情况下,如果上下文只包含一个 Servlet,它会被映射到 /。对于多个 servlet bean 的情况,bean 名称被用作路径前缀。Filter 映射到 /*

如果基于约定的映射不够灵活,您可以使用 ServletRegistrationBean、`FilterRegistrationBean`和 `ServletListenerRegistrationBean`类进行完全控制。

通常情况下,保持 filter bean 无序是安全的。如果需要特定顺序,您应该通过 @Order`注释 `Filter,或使其实现 Ordered。您无法通过使用 @Order`注释其 bean 方法来配置 `Filter`的顺序。如果您无法更改 `Filter`类来添加 `@Order`或实现 `Ordered,您必须为 Filter`定义一个 `FilterRegistrationBean,并使用 `setOrder(int)`方法设置注册 bean 的顺序。避免配置读取 `Ordered.HIGHEST_PRECEDENCE`的请求正文的 filter,因为它可能会违背您的应用程序的字符编码配置。如果一个 servlet filter 封装请求,它应被配置为一个小于或等于 `OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER`的顺序。

要查看您应用程序中每个 Filter`的顺序,请为 logging group(`logging.level.web=debug) 的 `web`启用调试级别日志。然后将在启动时记录已注册 filter 的详细信息,包括其顺序和 URL 模式。

在注册 Filter`bean 时要小心,因为它们在应用程序生命周期中很早就被初始化了。如果您需要注册一个与其他 bean 交互的 `Filter,请考虑使用 DelegatingFilterProxyRegistrationBean代替它。

Servlet Context Initialization

嵌入的 servlet 容器不会直接执行 `jakarta.servlet.ServletContainerInitializer`接口或者 Spring 的 `org.springframework.web.WebApplicationInitializer`接口。这是一个有意的设计决策,旨在降低为了在 war 中运行而设计的三方库可能破坏 Spring Boot 应用程序的风险。

如果你需要在一个 Spring Boot 应用程序中执行 servlet 的上下文初始化,就需要注册实现 org.springframework.boot.web.servlet.ServletContextInitializer 接口的 bean。单独的 onStartup 方法提供访问 ServletContext 的权限,并且有必要的时候,可以轻松用作一个已有的 WebApplicationInitializer 的适配器。

Scanning for Servlets, Filters, and listeners

当使用一个嵌入式容器时,可以通过使用 @ServletComponentScan 来启用带有注释 @WebServlet@WebFilter@WebListener 标记的类的自动注册。

@ServletComponentScan 在一个独立的容器中没有任何作用,容器的内置发现机制用在其中。

The ServletWebServerApplicationContext

底层中,Spring Boot 为嵌入式 servlet 容器支持使用了一种不同类型的 ApplicationContextServletWebServerApplicationContext 是一种特殊的 WebApplicationContext,它通过搜索一个 ServletWebServerFactory bean 来启动它自己。通常自动配置一个 TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactory

你通常不需要了解这些实现类。大多数应用程序都是自动配置的,适当的 ApplicationContextServletWebServerFactory 会为你创建。

在嵌入式容器设置中,ServletContext 作为服务器启动的一部分进行设置,这发生在应用程序上下文初始化过程中。由于这个原因,ApplicationContext 中的 bean 无法使用 ServletContext 可靠地进行初始化。解决此问题的一种方法是注入 ApplicationContext 作为该 bean 的一个依赖项,并且只有在需要时才访问 ServletContext。另一种方法是服务器启动后使用一个回调函数。这可以通过使用一个 ApplicationListener 来完成,它侦听 ApplicationStartedEvent,如下所示:

Customizing Embedded Servlet Containers

常见的 servlet 容器设置可以通过使用 Spring Environment 属性进行配置。通常,你在 application.propertiesapplication.yaml 文件中定义属性。

常见的服务器设置包括:

  • 网络设置:用于传入的 HTTP 请求的侦听端口 (server.port)、绑定到的接口地址 (server.address) 等。

  • 会话设置:会话是否持久 (server.servlet.session.persistent)、会话超时 (server.servlet.session.timeout)、会话数据的位置 (server.servlet.session.store-dir) 和会话 cookie 配置 (server.servlet.session.cookie.*)。

  • 错误管理:错误页的位置 (server.error.path) 等。

  • SSL

  • HTTP compression

Spring Boot 尽可能多地尝试公开常见设置,但这并不总是可能的。对于那些情况,专用名称空间提供服务器特定的自定义项(请参阅 server.tomcatserver.undertow)。例如,access logs 可以配置嵌入式 servlet 容器的特定功能。

请参阅 {code-spring-boot-autoconfigure-src}/web/ServerProperties.java[ServerProperties] 类以获取完整列表。

SameSite Cookies

SameSite cookie 属性可以由网络浏览器用来控制在跨站点请求中是否提交 cookie 以及如何提交 cookie。该属性对于已开始更改该属性缺失时使用的默认值的现代网络浏览器尤其相关。

如果你想更改会话 cookie 的 SameSite 属性,可以使用 configprop:server.servlet.session.cookie.same-site[] 属性。此属性受自动配置的 Tomcat、Jetty 和 Undertow 服务器支持。它还用于配置基于 servlet 的 Spring Session SessionRepository bean。

例如,如果你希望会话 cookie 具有 NoneSameSite 属性,可以将以下内容添加到 application.propertiesapplication.yaml 文件中:

server:
  servlet:
    session:
      cookie:
        same-site: "none"

如果你想更改添加到 HttpServletResponse 中的其他 cookie 上的 SameSite 属性,可以使用 CookieSameSiteSupplierCookieSameSiteSupplier 传递一个 Cookie 并且可以返回一个 SameSite 值或 null

有一些便利工厂和过滤器方法可以用来快速匹配特定 cookie。例如,添加以下 bean 会自动对名称匹配正则表达式 myapp.* 的所有 cookie 应用 LaxSameSite

Character Encoding

可以使用 server.servlet.encoding.* 配置属性配置处理请求和响应的嵌入式 servlet 容器的字符编码行为。

当请求的 Accept-Language 头指示请求的语言环境时,servlet 容器会自动将其映射到字符集。每个容器都提供默认的语言环境到字符集映射,你应验证它们是否满足应用程序的需求。如果不满足,请使用 configprop:server.servlet.encoding.mapping[] 配置属性自定义映射,如下例所示:

server:
  servlet:
    encoding:
      mapping:
        ko: "UTF-8"

在前一个示例中,ko(韩语)语言环境已映射到 UTF-8。这等同于传统 war 部署的 web.xml 文件中的 <locale-encoding-mapping-list> 条目。

Programmatic Customization

如果你需要从编程角度配置你的嵌入式 servlet 容器,你可以注册一个实现 WebServerFactoryCustomizer 的 Spring bean。WebServerFactoryCustomizer 允许访问 ConfigurableServletWebServerFactory,其中包含了许多定制的设置器方法。以下示例说明了如何以编程方式设置端口:

TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactoryConfigurableServletWebServerFactory 的专用变体,它们分别为 Tomcat、Jetty 和 Undertow 额外提供了定制设置器方法。以下示例演示了如何定制 TomcatServletWebServerFactory,从而可以访问 Tomcat 特有的配置选项:

Customizing ConfigurableServletWebServerFactory Directly

对于更高级的用例,你需要从 ServletWebServerFactory 扩展,你可以公开这样的 bean 类型。

为许多配置选项提供了设置器。还提供了若干受保护的方法 “hooks”,以防你需要执行更特殊的操作。有关详细信息,请参见 source code documentation

自动配置的定制器仍应用于你的自定义工厂,因此请小心使用该选项。

JSP Limitations

在运行使用嵌入式 servlet 容器(并打包为可执行归档文件)的 Spring Boot 应用程序时,JSP 支持有一些限制。

  • 使用 Jetty 和 Tomcat 时,如果使用 war 打包,它应该可以运行。当使用 java -jar 启动时,可执行 war 会运行,并且也能够部署到任何标准容器。使用可执行 jar 时,不支持 JSP。

  • Undertow 不支持 JSP。

  • 创建自定义 error.jsp 页面不会覆盖 error handling 的默认视图。Custom error pages 应该被用于代替。