20191114 Spring Boot官方文档学习(4.7)
4.7。开发Web应用程序
Spring Boot非常适合于Web应用程序开发。您可以使用嵌入式Tomcat,Jetty,Undertow或Netty创建独立的HTTP服务器。大多数Web应用程序都使用该spring-boot-starter-web
模块来快速启动和运行。您还可以选择使用spring-boot-starter-webflux
模块来构建反应式Web应用程序。
4.7.1。Spring Web MVC框架
在Spring Web MVC框架(通常简称为“Spring MVC”)是一个丰富的“模型视图控制器” Web框架。Spring MVC允许您创建特殊的@Controller
或@RestController
beans来处理传入的HTTP请求。控制器中的方法通过使用@RequestMapping
注解映射到HTTP 请求。
Spring MVC是核心Spring Framework的一部分,有关详细信息,请参阅参考文档。
Spring MVC自动配置
Spring Boot为Spring MVC提供了自动配置,可与大多数应用程序完美配合。
自动配置在Spring的默认值之上添加了以下功能:
- 包含
ContentNegotiatingViewResolver
和BeanNameViewResolver
。 - 支持服务静态资源,包括对WebJars的支持。
- 自动注册
Converter
,GenericConverter
和Formatter
beans。 - 支持
HttpMessageConverters
。 - 自动注册
MessageCodesResolver
。 - 静态
index.html
支持。 - 定制Favicon支持。
- 自动使用
ConfigurableWebBindingInitializer
bean。
如果您想保留Spring Boot MVC功能,并且想要添加其他MVC配置(拦截器,格式化程序,视图控制器和其他功能),则可以添加带@Configuration
注解的WebMvcConfigurer
类,但不添加 @EnableWebMvc
。如果您希望提供自定义实例RequestMappingHandlerMapping
、RequestMappingHandlerAdapter
或ExceptionHandlerExceptionResolver
,则可以声明一个WebMvcRegistrationsAdapter
实例来提供此类组件。
如果您想完全控制Spring MVC,可以使用添加自己的使用@EnableWebMvc
的@Configuration
类。
参考源码:
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
HttpMessageConverters
Spring MVC使用HttpMessageConverter
接口来转换HTTP请求和响应。开箱即用中包含明智的默认设置。例如,可以将对象自动转换为JSON
(通过使用Jackson库)或XML
(通过使用Jackson XML扩展(如果可用)或通过使用JAXB(如果Jackson XML扩展不可用))。默认情况下,字符串编码为UTF-8
。
参考源码:
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#addDefaultHttpMessageConverters
如果您需要添加或自定义转换器,则可以使用Spring Boot的HttpMessageConverters
类,如下所示:
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
}
}
上下文中存在的任何HttpMessageConverter
Bean都将添加到转换器列表中。您也可以用相同的方法覆盖默认转换器。
自定义JSON序列化器和反序列化器
如果使用Jackson来序列化和反序列化JSON数据,则可能需要编写自己的JsonSerializer
和JsonDeserializer
类。自定义序列化程序通常是通过模块向Jackson进行注册的,但是Spring Boot提供了另一种选择,使用@JsonComponent
注解直接注册Spring Beans。
您可以使用@JsonComponent
直接的注解JsonSerializer
,JsonDeserializer
或KeyDeserializer
实现。您还可以在包含序列化器/反序列化器作为内部类的类上使用@JsonComponent
,如以下示例所示:
import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;
@JsonComponent
public class Example {
public static class Serializer extends JsonSerializer<SomeObject> {
// ...
}
public static class Deserializer extends JsonDeserializer<SomeObject> {
// ...
}
}
所有ApplicationContext
中的@JsonComponent
beans都会自动向Jackson注册。因为@JsonComponent
使用@Component
进行了元注释,所以适用通常的组件扫描规则。
Spring Boot还提供了JsonObjectSerializer
和JsonObjectDeserializer
基类,使用它们来实现Jackson序列反序列器更简单。
MessageCodesResolver
Spring MVC的具有从绑定错误中为渲染错误消息产生错误代码的策略:MessageCodesResolver
。如果您设置spring.mvc.message-codes-resolver-format
属性为PREFIX_ERROR_CODE
或POSTFIX_ERROR_CODE
,Spring Boot会为您创建一个MessageCodesResolver
。参考源码:org.springframework.validation.DefaultMessageCodesResolver.Format
。
静态内容
默认情况下,Spring Boot从类路径中名为/static
(或/public
、/resources
、/META-INF/resources
)的目录或ServletContext
根目录中提供静态内容。它使用Spring MVC中的ResourceHttpRequestHandler
,因此您可以通过添加自己WebMvcConfigurer
并覆盖addResourceHandlers
方法来修改该行为。
在独立的Web应用程序中,还启用了容器中的默认servlet,并将其用作fallback,从Spring决定不处理它,ServletContext的根开始提供内容。在大多数情况下,这不会发生(除非您修改默认的MVC配置),因为Spring始终可以通过DispatcherServlet
处理请求。
默认情况下,资源映射到/**
,但是您可以使用spring.mvc.static-path-pattern
属性对其进行调整。例如,将所有资源重新定位/resources/**
可以通过以下方式实现:
spring.mvc.static-path-pattern=/resources/**
参考源码:
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#addResourceHandlers
您还可以通过使用spring.resources.static-locations
属性来自定义静态资源位置(用一些目录位置替换默认值)。根Servlet上下文路径,也会自动添加为 "/
" 一个位置。
除了前面提到的“标准”静态资源位置,Webjars内容也有特殊情况。如果jar文件以Webjars格式打包,则从jar文件提供带有路径/webjars/**
的所有资源。
如果您的应用程序打包为jar,则不要使用src/main/webapp
目录。尽管此目录是一个通用标准,但它仅与war打包一起使用,如果生成jar,大多数构建工具都将其忽略。
Spring Boot还支持Spring MVC提供的高级资源处理功能,例如缓存清除静态资源或对Webjars使用版本无关的URL。
要对Webjar使用版本无关的URL,请添加webjars-locator-core
依赖项。然后声明您的Webjar。以jQuery为例,将版本为x.y.z的jQuery,即"/webjars/jquery/x.y.z/jquery.min.js",添加为"/webjars/jquery/jquery.min.js"结果。
如果使用JBoss,则需要声明webjars-locator-jboss-vfs
依赖关系而不是webjars-locator-core
。否则,所有Webjar都将解析为404。
要使用缓存清除,以下配置为所有静态资源配置了缓存清除解决方案,从而有效地在URL中添加了内容哈希,例如<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
由于为Thymeleaf和FreeMarker自动配置了ResourceUrlEncodingFilter
,因此在运行时可以在模板中重写资源链接。使用JSP时,您应该手动声明此过滤器。目前尚不自动支持其他模板引擎,但可以与自定义模板宏/帮助程序一起使用,也可以使用ResourceUrlProvider
。
例如,当使用JavaScript模块加载器动态加载资源时,不能重命名文件。这就是为什么其他策略也受支持并且可以组合的原因。“固定”策略在URL中添加静态版本字符串,而不更改文件名,如以下示例所示:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/lib/
spring.resources.chain.strategy.fixed.version=v12
通过这种配置,位于"/js/lib/"下面的JavaScript模块使用固定的版本控制策略("/v12/js/lib/mymodule.js"),而其他资源仍使用内容版本(<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
)。
更多配置参考
org.springframework.boot.autoconfigure.web.ResourceProperties
欢迎页面
Spring Boot支持静态和模板欢迎页面。它首先在配置的静态内容位置中查找index.html
文件。如果未找到,则寻找index模板。如果找到任何一个,它将自动用作应用程序的欢迎页面。
自定义图标
与其他静态资源一样,Spring Boot 在配置的静态内容位置中查找favicon.ico
。如果存在这样的文件,它将自动用作应用程序的图标。
路径匹配和内容协商
Spring MVC可以通过查看请求路径并将其匹配到应用程序中定义的映射(例如,Controller
方法上的@GetMapping
注解)来将传入的HTTP请求映射到处理程序。
Spring Boot默认选择禁用后缀模式匹配,这意味着类似"GET /projects/spring-boot.json
"的请求将不会与@GetMapping("/projects/spring-boot")
映射匹配。这被认为是Spring MVC应用程序的最佳实践。过去,此功能主要用于未发送正确的“Accept”请求标头的HTTP客户端。我们需要确保将正确的内容类型发送给客户端。如今,内容协商已变得更加可靠。
还有其他处理HTTP客户端的方法,这些客户端不能始终发送正确的“Accept”请求标头。除了使用后缀匹配,我们还可以使用查询参数来确保将诸如"GET /projects/spring-boot?format=json
"这样的请求映射到@GetMapping("/projects/spring-boot")
:
# 是否以请求参数(默认是format)决定请求的内容类型
spring.mvc.contentnegotiation.favor-parameter=true
# 修改默认参数,默认为format
spring.mvc.contentnegotiation.parameter-name=myparam
# 注册额外的文件扩展名
spring.mvc.contentnegotiation.media-types.pdf=application/json
如果您了解了注意事项,但仍希望您的应用程序使用后缀模式匹配,则需要以下配置:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-suffix-pattern=true
另外,与其打开所有后缀模式,不如仅支持已注册的后缀模式,这会更安全:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-registered-suffix-pattern=true
ConfigurableWebBindingInitializer
Spring MVC为特殊的请求使用WebBindingInitializer
初始化WebDataBinder
。如果创建自己的ConfigurableWebBindingInitializer
@Bean,Spring Boot会自动将Spring MVC配置为使用它。
模板引擎
除了REST Web服务之外,您还可以使用Spring MVC来提供动态HTML内容。Spring MVC支持各种模板技术,包括Thymeleaf,FreeMarker和JSP。同样,许多其他模板引擎包括他们自己的Spring MVC集成。
Spring Boot包含对以下模板引擎的自动配置支持:
- FreeMarker
- Groovy
- Thymeleaf
- Mustache
应避免使用JSP。将它们与嵌入式servlet容器一起使用时,存在几个已知的限制。
在默认配置下使用这些模板引擎之一时,将从src/main/resources/templates
中自动提取模板。
根据您运行应用程序的方式,IntelliJ IDEA对类路径的排序不同。与使用Maven或Gradle或从其打包的jar运行应用程序时相比,从IDE的主要方法运行应用程序的顺序会有所不同。这可能导致Spring Boot无法在类路径上找到模板。如果遇到此问题,可以在IDE中重新排序类路径,以首先放置模块的类和资源。或者,您可以配置模板前缀来搜索templates类路径上的每个目录,如下所示:classpath*:/templates/
。
错误处理
默认情况下,Spring Boot提供了/error
映射所有错误,并且已在servlet容器中注册为“全局”错误页面。对于机器客户端,它将生成一个JSON响应,其中包含错误详情,HTTP状态和异常消息的详细信息。对于浏览器客户端,存在一个“ whitelabel”错误视图,该视图以HTML格式呈现相同的数据(要对其进行自定义,请添加View解析为error)。要完全替换默认行为,可以实现ErrorController
并注册该类型的Bean定义,或添加ErrorAttributes
类型的Bean以使用现有机制但替换其内容。
BasicErrorController
可以用作基类自定义ErrorController
。如果您要为新的内容类型添加handler(默认专门处理text/html并为其他所有内容提供fallback功能),则此功能特别有用。为此,请扩展BasicErrorController
,添加一个具有produces
属性的@RequestMapping
公共方法,并创建一个新类型的Bean。
您还可以定义带有@ControllerAdvice
注解的类,以自定义JSON文档以针对特定的控制器和/或异常类型返回,如以下示例所示:
@ControllerAdvice(basePackageClasses = MyController.class)
public class AcmeControllerAdvice extends ResponseEntityExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable
ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
自定义错误页面
如果要显示给定状态代码的自定义HTML错误页面,可以将文件添加到/error
文件夹。错误页面可以是静态HTML(即添加到任何静态资源文件夹下),也可以使用模板来构建。文件名应为确切的状态代码或系列掩码。
例如,要映射404到静态HTML文件,您的文件夹结构如下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
可以使用5xx来映射5xx的错误。
对于更复杂的映射,还可以添加实现ErrorViewResolver
接口的bean ,如以下示例所示:
@Component
public class MyErrorViewResolver implements ErrorViewResolver {
@Override
public ModelAndView resolveErrorView(HttpServletRequest request,
HttpStatus status, Map<String, Object> model) {
// Use the request or status to optionally return a ModelAndView
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("test.html");
return modelAndView;
}
}
您还可以使用常规的Spring MVC功能,例如@ExceptionHandler
方法和@ControllerAdvice
。ErrorController
随后处理任何未处理的异常。
在Spring MVC之外映射错误页面
对于不使用Spring MVC的应用程序,您可以使用ErrorPageRegistrar
接口直接注册ErrorPages
。此抽象直接与基础嵌入式servlet容器一起使用,即使您没有Spring MVC也可以使用DispatcherServlet
。
@Bean
public ErrorPageRegistrar errorPageRegistrar(){
return new MyErrorPageRegistrar();
}
// ...
private static class MyErrorPageRegistrar implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
}
}
如果您使用最终由Filter处理的路径注册ErrorPage(这在某些非Spring Web框架中很常见,例如Jersey和Wicket),则Filter必须将其显式注册为ERROR调度程序,如以下示例所示:
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
...
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}
请注意,默认的FilterRegistrationBean
不包括ERROR调度程序类型。
注意:当部署到servlet容器时,Spring Boot将使用其错误页面过滤器将具有错误状态的请求转发到适当的错误页面。请求只能在尚未提交响应的情况下转发到正确的错误页面。缺省情况下,WebSphere Application Server 8.0及更高版本在成功完成servlet的服务方法后提交响应。您应该通过设置com.ibm.ws.webcontainer.invokeFlushAfterService
为false来禁用此行为。
Spring HATEOAS
如果您开发使用超媒体的RESTful API,Spring Boot将为Spring HATEOAS提供自动配置,该配置可与大多数应用程序很好地兼容。自动配置取代了使用@EnableHypermediaSupport
和注册大量Bean的需求,以简化构建基于超媒体的应用程序,包括LinkDiscoverers
(用于客户端支持)和ObjectMapper
配置为正确地将响应编组为所需表示形式的Bean 。ObjectMapper是通过设置spring.jackson.*
属性来定制的,或者,如果存在一个Jackson2ObjectMapperBuilder
Bean。
您可以使用@EnableHypermediaSupport
来控制Spring HATEOAS的配置。请注意,这样做会禁用前面所述的自定义ObjectMapper。
Spring HATEOAS的其他参考文档
CORS支持
跨域资源共享(CORS)是由大多数浏览器实施的W3C规范,可让您灵活地指定授权哪种类型的跨域请求,而不是使用诸如IFRAME或JSONP之类的安全性较低,功能较弱的方法。
从4.2版本开始,Spring MVC 支持CORS。在Spring Boot应用程序中使用带有@CrossOrigin
注解的CORS配置的控制器方法不需要任何特定的配置。可以通过使用自定义方法WebMvcConfigurer#addCorsMappings(CorsRegistry)
来定义全局CORS配置,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**");
}
};
}
}
4.7.2。“ Spring WebFlux框架”
Spring WebFlux
是Spring Framework 5.0中引入的新的响应式Web框架。与Spring MVC不同,它不需要Servlet API,是完全异步和非阻塞的,并且通过Reactor项目实现Reactive Streams规范。
Spring WebFlux有两种形式:函数式的和基于注解的。基于注解的模型非常类似于Spring MVC模型,如以下示例所示:
@RestController
@RequestMapping("/users")
public class MyRestController {
@GetMapping("/{user}")
public Mono<User> getUser(@PathVariable Long user) {
// ...
}
@GetMapping("/{user}/customers")
public Flux<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}
@DeleteMapping("/{user}")
public Mono<User> deleteUser(@PathVariable Long user) {
// ...
}
}
函数式变体“WebFlux.fn”将路由配置与请求的实际处理分开,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class RoutingConfiguration {
@Bean
public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
}
}
@Component
public class UserHandler {
public Mono<ServerResponse> getUser(ServerRequest request) {
// ...
}
public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
// ...
}
public Mono<ServerResponse> deleteUser(ServerRequest request) {
// ...
}
}
WebFlux是Spring Framework的一部分,其参考文档中提供了详细信息。
您可以根据需要定义任意数量的RouterFunction
beans,以对路由器的定义进行模块化。如果需要应用优先级,可以对Bean排序。
首先,将spring-boot-starter-webflux
模块添加到您的应用程序。
在应用程序中 同时添加spring-boot-starter-web
和spring-boot-starter-webflux
模块会导致Spring Boot自动配置Spring MVC,而不是WebFlux。之所以选择这种行为,是因为许多Spring开发人员将spring-boot-starter-webflux
添加到他们的Spring MVC应用程序中以使用反应式WebClient。您仍然可以通过将选定的应用程序类型设置为REACTIVE来强制执行选择:SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)
。
Spring WebFlux自动配置
Spring Boot为Spring WebFlux提供了自动配置,在Spring的默认值之上添加了以下功能:
为HttpMessageReader
和HttpMessageWriter
实例配置编解码器)。
支持服务静态资源,包括对WebJars的支持。
参考源码:
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration
如果您想保留Spring Boot WebFlux功能并想要添加其他WebFlux配置,则可以添加WebFluxConfigurer
类型的@Configuration
类,但不添加 @EnableWebFlux
。
如果要完全控制Spring WebFlux,可以使用添加自己的带@EnableWebFlux
注解@Configuration
类。
带有HttpMessageReaders
和HttpMessageWriters
的HTTP编解码器
Spring WebFlux使用HttpMessageReader
和HttpMessageWriter
接口转换HTTP请求和响应。CodecConfigurer
通过查看类路径中可用的库,将它们配置为具有合理的默认值。
Spring Boot通过使用CodecCustomizer
实例进一步定制。例如,将spring.jackson.*
配置应用于Jackson编解码器。
如果需要添加或自定义编解码器,则可以创建一个自定义CodecCustomizer
组件,如以下示例所示:
import org.springframework.boot.web.codec.CodecCustomizer;
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public CodecCustomizer myCodecCustomizer() {
return codecConfigurer -> {
// ...
}
}
}
您还可以利用Boot的自定义JSON序列化器和反序列化器。
静态内容
默认情况下,Spring Boot从类路径中名为/static
(/public
或/resources
或/META-INF/resources
)的目录(参考org.springframework.boot.autoconfigure.web.ResourceProperties#CLASSPATH_RESOURCE_LOCATIONS
)中提供静态内容。它使用Spring WebFlux中的ResourceWebHandler
,因此您可以通过添加WebFluxConfigurer
的addResourceHandlers
方法并来修改该行为。
默认情况下,资源映射在/**
上,但是您可以通过设置spring.webflux.static-path-pattern
属性来对其进行调整。例如,将所有资源重新定位/resources/**
可以通过以下方式实现:
spring.webflux.static-path-pattern=/resources/**
您还可以使用spring.resources.static-locations
来自定义静态资源位置。这样做会将默认值替换为目录位置列表。如果这样做,默认的欢迎页面检测将切换到您的自定义位置。因此,如果启动时您的任何位置都有index.html
,则为应用程序的主页。
除了前面列出的“标准”静态资源位置外,Webjars内容也有特殊情况。如果jar文件以Webjars格式打包,则从jar文件提供带有/webjars/**
路径的所有资源。
Spring WebFlux应用程序不严格依赖Servlet API,因此不能将它们部署为war文件,也不使用src/main/webapp
目录。
模板引擎
除了REST Web服务之外,您还可以使用Spring WebFlux来提供动态HTML内容。Spring WebFlux支持各种模板技术,包括Thymeleaf,FreeMarker和Mustache。
在默认配置下使用这些模板引擎之一时,将从src/main/resources/templates
中自动提取模板。
错误处理
Spring Boot提供了WebExceptionHandler
以合理的方式处理所有错误的工具。它在处理顺序中的位置紧靠WebFlux
提供的处理程序之前,该处理程序被认为是最后一个。对于机器客户端,它将生成一个JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。对于浏览器客户端,有一个“ whitelabel”错误处理程序,以HTML格式呈现相同的数据。您还可以提供自己的HTML模板来显示错误。
定制此功能的第一步通常涉及使用现有机制,但替换或增加错误内容。为此,您可以添加类型为ErrorAttributes
的bean。
要更改错误处理行为,可以实现ErrorWebExceptionHandler
并注册该类型的bean定义。由于WebExceptionHandler
级别很低,因此Spring Boot还提供了一种方便的AbstractErrorWebExceptionHandler
,使您可以通过WebFlux功能方式处理错误,如以下示例所示:
public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
// Define constructor here
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions
.route(aPredicate, aHandler)
.andRoute(anotherPredicate, anotherHandler);
}
}
为了获得更完整的控制,您还可以直接继承DefaultErrorWebExceptionHandler
并覆盖特定的方法。
网页过滤器
Spring WebFlux提供了可以实现以过滤HTTP请求-响应交换的WebFilter
接口。 在应用程序上下文中找到的WebFilter bean将自动用于过滤每个交换。
如果过滤器的顺序很重要,则可以实现Ordered
接口或添加@Order
注解。Spring Boot自动配置可能会为您配置Web过滤器。这样做时,将使用下表中显示的顺序:
Web Filter | Order |
---|---|
MetricsWebFilter | Ordered.HIGHEST_PRECEDENCE + 1 |
WebFilterChainProxy | (Spring Security) -100 |
HttpTraceWebFilter | Ordered.LOWEST_PRECEDENCE - 10 |
4.7.3。JAX-RS和Jersey
如果您更喜欢REST端点的JAX-RS编程模型,可以使用可用的实现之一来代替Spring MVC。 Jersey和Apache CXF开箱即用。CXF需要您在应用程序上下文注册其Servlet或Filter为@Bean。Jersey提供了一些原生的Spring支持,因此我们在Spring Boot中还与Starter一起为其提供了自动配置支持。
要开始使用Jersey,请包含spring-boot-starter-jersey
为依赖项,然后需要使用ResourceConfig
@Bean类型注册所有端点,如以下示例所示:
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
}
}
Jersey对扫描可执行归档文件的支持非常有限。例如,它无法扫描在完全可执行的jar文件中或在运行可执行的war文件时在WEB-INF/classes
包中找到的端点。为避免此限制,不应该使用packages方法,并且应该使用register方法分别注册端点,如前面的示例所示。
对于更高级的自定义,您还可以注册任意数量的实现的ResourceConfigCustomizer
Bean。
所有注册的端点都应带有@Components
和HTTP资源注释(@GET及其他注释),如以下示例所示:
@Component
@Path("/hello")
public class Endpoint {
@GET
public String message() {
return "Hello";
}
}
由于Endpoint
是Spring @Component,因此其生命周期由Spring管理,您可以使用@Autowired
注解注入依赖项,并使用@Value
注解注入外部配置。默认情况下,Jersey servlet已注册并映射到 /*
。您可以通过添加@ApplicationPath
改变映射到ResourceConfig
。
默认情况下,Jersey被设置为一个类型为ServletRegistrationBean
,命名为jerseyServletRegistration
的Servlet 的@Bean。默认情况下,该Servlet延迟初始化,但是您可以通过设置spring.jersey.servlet.load-on-startup
来自定义该行为。您可以通过创建自己的同名bean来禁用或覆盖该bean。您还可以通过设置spring.jersey.type=filter
使用Filter而不是Servlet(在这种情况下,要替换或覆盖的是jerseyFilterRegistration
@Bean)。过滤器具有@Order
,您可以使用spring.jersey.filter.order
设置。可以通过spring.jersey.init.*
指定属性映射来为servlet和过滤器注册都赋予init参数。
4.7.4。嵌入式Servlet容器支持
Spring Boot包含对嵌入式Tomcat,Jetty和Undertow服务器的支持。大多数开发人员使用适当的Starter来获取完全配置的实例。默认情况下,嵌入式服务器在侦听8080
端口。
Servlet,Filter和Lisener
使用嵌入式Servlet容器时,您可以使用Spring Bean或扫描Servlet组件来注册Servlet规范中的Servlet
,Filter
和所有Lisener
(例如HttpSessionListener
)。
将Servlet,Filter和Lisener注册为Spring Bean
作为Spring bean的任何Servlet,Filter或servlet *Listener 实例都向嵌入式容器注册。如果要在配置application.properties过程中引用一个值,这将特别方便。
默认情况下,如果上下文仅包含单个Servlet,则将其映射到/
。对于多个servlet bean,bean名称用作路径前缀。过滤器映射到/*
。
如果以公约为映射不够灵活,你可以使用ServletRegistrationBean
,FilterRegistrationBean
以及ServletListenerRegistrationBean
类进行完全控制。
可以添加@Order
注解或实现Ordered
接口,以控制其在过滤链中的位置。通常可以使过滤器beans处于无序状态。但是,如果需要特定的顺序,则应避免配置一个在读取请求正文的过滤器为Ordered.HIGHEST_PRECEDENCE
,因为它可能与应用程序的字符编码配置不符。如果Servlet过滤器包装了请求,则应以小于或等于OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER
的顺序对其进行配置。
要查看应用程序中每个Filter组件的顺序,请为web 日志记录组启用调试级别的日志记录(logging.level.web=debug
)。然后,将在启动时记录已注册过滤器的详细信息,包括其顺序和URL模式。
注册Filter bean 时要小心,因为它们是在应用程序生命周期中很早就初始化的。如果您需要注册一个Filter与其他bean交互的,请考虑使用DelegatingFilterProxyRegistrationBean
。
Servlet上下文初始化
嵌入式Servlet容器不会直接执行Servlet 3.0+ 的javax.servlet.ServletContainerInitializer
接口或Spring的org.springframework.web.WebApplicationInitializer
接口。这是一个有意的设计决定,旨在降低在war中运行的第三方库可能破坏Spring Boot应用程序的风险。
如果您需要在Spring Boot应用程序中执行servlet上下文初始化,则应该注册一个实现org.springframework.boot.web.servlet.ServletContextInitializer
接口的bean 。onStartup
方法提供对ServletContext
的访问,并且在必要时可以轻松用作现有WebApplicationInitializer
的适配器。
扫描Servlet,Filter和Listener
当使用嵌入式容器中,可以通过使用@ServletComponentScan
启用对@WebServlet
,@WebFilter
和@WebListener
的自动配置。
@ServletComponentScan
在独立的容器中无效,而是使用容器的内置发现机制。
ServletWebServerApplicationContext
在后台,Spring Boot 对嵌入式servlet容器使用了不同类型的ApplicationContext支持。ServletWebServerApplicationContext
是一种特殊类型的WebApplicationContext通过搜索单个ServletWebServerFactory
bean引导自身。通常是TomcatServletWebServerFactory
,JettyServletWebServerFactory
或UndertowServletWebServerFactory
已被自动配置。
通常,您不需要了解这些实现类。大多数应用程序都自动配置,并且适当的ApplicationContext和ServletWebServerFactory已创建。
自定义嵌入式Servlet容器
可以使用Spring Environment属性来配置通用的servlet容器设置。通常,您将在application.properties文件中定义属性。
通用服务器设置包括:
- 网络设置:侦听传入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压缩
Spring Boot尝试尽可能多地公开通用设置,但这并不总是可能的。在这种情况下,专用名称空间提供服务器特定的定制属性(请参阅server.tomcat
和server.undertow
)。例如,可以使用嵌入式servlet容器的特定功能配置访问日志。
更多配置参考:
org.springframework.boot.autoconfigure.web.ServerProperties
以编程方式定制
如果需要以编程方式配置嵌入式servlet容器,则可以注册一个实现WebServerFactoryCustomizer
接口的Spring bean 。 WebServerFactoryCustomizer
提供对ConfigurableServletWebServerFactory
的访问,其中包括许多自定义setter方法。以下示例显示以编程方式设置端口:
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;
@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}
}
TomcatServletWebServerFactory
,JettyServletWebServerFactory
和UndertowServletWebServerFactory
是ConfigurableServletWebServerFactory
的专用变体,具有分别用于Tomcat, Jetty 和 Undertow的额外定制setter方法。
直接自定义ConfigurableServletWebServerFactory
如果前面的定制技术太有限,你可以直接注册TomcatServletWebServerFactory
,JettyServletWebServerFactory
或UndertowServletWebServerFactory
bean。
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
return factory;
}
提供了许多配置选项的setter。如果您需要做一些更奇特的操作,还提供了几种受保护的方法“挂钩”。更多信息参考:
org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory
JSP局限性
运行使用嵌入式servlet容器(并打包为可执行Jar)的Spring Boot应用程序时,JSP支持存在一些限制。
- 对于Jetty和Tomcat,如果使用war打包,它应该可以工作。使用java -jar启动时,可执行的War将起作用,并且也可部署到任何标准容器中。使用可执行jar时,不支持JSP。
- Undertow不支持JSP。
- 创建自定义error.jsp页面不会覆盖错误处理的默认视图。 应改用自定义错误页面。
4.7.5。嵌入式反应式服务器支持
Spring Boot包含对以下嵌入式反应式Web服务器的支持:Reactor Netty,Tomcat,Jetty和Undertow。大多数开发人员使用适当的Starter来获取完全配置的实例。默认情况下,嵌入式服务器在端口8080上侦听HTTP请求。
4.7.6。反应性服务器资源配置
在自动配置Reactor Netty或Jetty服务器时,Spring Boot将创建特定的bean,这些bean将向服务器实例提供HTTP资源:ReactorResourceFactory
或JettyResourceFactory
。
默认情况下,这些资源还将与Reactor Netty和Jetty客户端共享,以实现最佳性能,前提是:
- 服务器和客户端使用相同的技术
- 客户端实例是使用Spring Boot自动配置的
WebClient.Builder
bean 构建的
开发人员可以通过提供一个自定义ReactorResourceFactory
或JettyResourceFactory
bean 来覆盖Jetty和Reactor Netty的资源配置,这将同时应用于客户端和服务器。