SpringBoot学习笔记11-Web-Reactive Web应用

以spring官方文档为基础,官方地址:Spring Boot_Web

Spring Boot非常适合web应用程序的开发。可以使用嵌入的Tomcat、Jetty、Undertow或Netty创建一个自包含的HTTP服务器。大多数web应用程序使用spring-boot-starter-web模块来快速启动和运行。也可以选择使用spring-boot-starter-webflux模块来构建响应式web应用程序。

Spring Boot通过为Spring Webflux提供自动配置,简化了响应式web应用程序的开发。

1. 关于Spring WebFlux Framework

Spring WebFlux是Spring framework 5.0中引入的一个新的响应式web框架。与Spring MVC不同,它不需要servlet API,是完全异步和非阻塞的,并通过Reactor项目实现了Reactive Streams规范。

Spring WebFlux有两种类型:功能性和基于注解的。基于注解的模型非常接近Spring MVC模型,如下面的例子所示:

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/users")
public class MyRestController {

    private final UserRepository userRepository;

    private final CustomerRepository customerRepository;

    public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {
        this.userRepository = userRepository;
        this.customerRepository = customerRepository;
    }

    @GetMapping("/{user}")
    public Mono<User> getUser(@PathVariable Long userId) {
        return this.userRepository.findById(userId);
    }

    @GetMapping("/{user}/customers")
    public Flux<Customer> getUserCustomers(@PathVariable Long userId) {
        return this.userRepository.findById(userId).flatMapMany(this.customerRepository::findByUser);
    }

    @DeleteMapping("/{user}")
    public void deleteUser(@PathVariable Long userId) {
        this.userRepository.deleteById(userId);
    }

}

WebFlux是Spring框架的一部分,详细信息可以在它的参考文档中找到。

还有WebFlux,首先,将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。但是仍然可以通过将选择的应用类型设置为SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)来强制你的选择。

1.1 Spring WebFlux的自动配置

Spring Boot为Spring WebFlux提供了自动配置,它在大多数应用程序中都能很好地工作。

WebFlux的自动配置,在Spring的默认值之上添加了以下特性:

  • 为HttpMessageReader和HttpMessageWriter实例配置编解码器(在本文档后面描述)。

  • 支持提供静态资源,包括对webjar的支持(在本文档后面描述)。

如果想保持Spring Boot WebFlux的特性,并且想添加额外的WebFlux配置,可以添加自己的WebFluxConfigurer类型的@Configuration类,但不要添加@EnableWebFlux。

如果想完全控制Spring WebFlux,可以添加自己的@Configuration和@EnableWebFlux注释。

1.2 HttpMessageReaders和HttpMessageWriters的HTTP编解码器

Spring WebFlux使用HttpMessageReader和HttpMessageWriter接口来转换HTTP请求和响应。它们使用CodecConfigurer进行了配置,通过查看类路径中可用的库来拥有合理的默认值。

Spring Boot为编解码器提供了专用的配置属性Spring .codec.*。它还通过使用CodecCustomizer实例应用进一步的定制。例如,spring.jackson.*配置键应用于Jackson编解码器。

如果需要添加或自定义codecs,可以创建一个自定义CodecCustomizer组件,示例如下:

import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.codec.ServerSentEventHttpMessageReader;

@Configuration(proxyBeanMethods = false)
public class MyCodecsConfiguration {

    @Bean
    public CodecCustomizer myCodecCustomizer() {
        return (configurer) -> {
            configurer.registerDefaults(false);
            configurer.customCodecs().register(new ServerSentEventHttpMessageReader());
            // ...
        };
    }

}

默认情况下,Spring Boot服务于类路径中一个名为/static(或/public或/resources或/META-INF/resources)的目录中的静态内容。它使用来自Spring WebFlux的ResourceWebHandler,这样就可以通过添加自己的WebFluxConfigurer和覆盖addResourceHandlers方法来修改该行为。

默认情况下,资源被映射到/**上,但是您可以通过设置spring.webflux来优化它。static-path-pattern财产。例如,重新定位所有资源到/resources/**可以实现如下:

spring.webflux.static-path-pattern=/resources/**

也可以使用spring.web.resources.static-locations自定义静态资源位置。这样做将用目录位置列表替换默认值。如果这样做,默认的欢迎页面检测将切换到你的自定义位置。因此,如果在启动时的任何位置都有index.html,那么它就是应用程序的主页。

除了前面列出的“标准”静态资源位置外,Webjars内容也有特殊情况。任何路径在/webjars/**中的资源,如果它们是以webjars格式打包的,则会从jar文件中提供。

1.3 Welcome Page

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

1.4 模板引擎

和REST web服务一样,也可以使用Spring WebFlux来提供动态HTML内容。Spring WebFlux支持多种模板技术,包括Thymeleaf、FreeMarker和Mustache。
Spring Boot包括对以下模板引擎的自动配置支持:

  • FreeMarker
  • Thymeleaf
  • Mustache

当使用以上模板引擎的默认配置时,你的模板会自动从src/main/resources/templates中选取。

1.5 错误处理

Spring Boot提供了一个WebExceptionHandler ,它以一种合理的方式处理所有错误。它在处理顺序中的位置在WebFlux提供的处理程序之前,后者被认为是最后的。对于机器客户端,它会生成一个JSON响应,其中包含错误、HTTP状态和异常消息的详细信息。对于浏览器客户端,有一个“白标签”错误处理程序,它以HTML格式呈现相同的数据。还可以提供自己的HTML模板来显示错误。

定制此特性的第一步通常涉及使用现有机制,但替换或增加错误内容。为此,可以添加一个ErrorAttributes类型的bean。

要更改错误处理行为,可以实现ErrorWebExceptionHandler并注册该类型的bean定义。因为ErrorWebExceptionHandler是相当低级的,所以Spring Boot也提供了一个方便的AbstractErrorWebExceptionHandler来让你用WebFlux函数的方式处理错误,如下面的例子所示:

import reactor.core.publisher.Mono;

import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.function.server.ServerResponse.BodyBuilder;

@Component
public class MyErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {

    public MyErrorWebExceptionHandler(ErrorAttributes errorAttributes, Resources resources,
            ApplicationContext applicationContext) {
        super(errorAttributes, resources, applicationContext);
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml);
    }

    private boolean acceptsXml(ServerRequest request) {
        return request.headers().accept().contains(MediaType.APPLICATION_XML);
    }

    public Mono<ServerResponse> handleErrorAsXml(ServerRequest request) {
        BodyBuilder builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR);
        // ... additional builder calls
        return builder.build();
    }

}

要了解更全面的情况,还可以直接子类化DefaultErrorWebExceptionHandler并重写特定的方法。

在某些情况下,在控制器或处理程序函数级别处理的错误不会被度量基础设施记录下来。通过将处理的异常设置为请求属性,应用程序可以确保这些异常被记录在请求度量中:

import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.reactive.result.view.Rendering;
import org.springframework.web.server.ServerWebExchange;

@Controller
public class MyExceptionHandlingController {

    @GetMapping("/profile")
    public Rendering userProfile() {
        // ...
        throw new IllegalStateException();
    }

    @ExceptionHandler(IllegalStateException.class)
    public Rendering handleIllegalState(ServerWebExchange exchange, IllegalStateException exc) {
        exchange.getAttributes().putIfAbsent(ErrorAttributes.ERROR_ATTRIBUTE, exc);
        return Rendering.view("errorView").modelAttribute("message", exc.getMessage()).build();
    }

}

1.6 自定义错误页面

如果希望为给定的状态码显示自定义HTML错误页面,可以向/error目录中添加一个文件。错误页面可以是静态HTML(也就是说,添加到任何静态资源目录下),也可以用模板构建。文件的名称应该是确切的状态码或系列掩码。

例如,将404映射到一个静态HTML文件,目录结构可如下:

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

使用Mustache模板映射所有5xx错误,目录结构可如下:

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

1.7 Web过滤器

Spring WebFlux提供了一个WebFilter接口,可以实现这个接口来过滤HTTP请求-响应交换。在应用程序上下文中找到的WebFilter bean将自动用于过滤每个交换。

在筛选器的顺序很重要的地方,它们可以实现Ordered或使用@Order进行注释。Spring Boot自动配置可以为其配置web过滤器。比如以下过滤器示例中的顺序:

Web Filter Order
MetricsWebFilter Ordered.HIGHEST_PRECEDENCE + 1
WebFilterChainProxy (Spring Security) -100
HttpTraceWebFilter Ordered.LOWEST_PRECEDENCE - 10

2. 嵌入式响应式服务器支持

Spring Boot支持以下嵌入式响应式web服务器:Reactor Netty、Tomcat、Jetty和Undertow。大多数开发人员使用适当的“Starter”来获得完全配置的实例。默认情况下,嵌入式服务器在端口8080上侦听HTTP请求。

3. 响应式服务器资源配置

当自动配置Reactor Netty或Jetty服务器时,Spring Boot将创建特定的bean,这些bean将为服务器实例提供HTTP资源:ReactorResourceFactory或JettyResourceFactory。

默认情况下,这些资源也将与Reactor Netty和Jetty客户端共享,以获得最佳性能:

  • 同样的技术也用于服务器和客户端
  • 客户端实例是使用WebClient构建的。Spring Boot会自动配置Builder bean

开发人员可以通过提供一个自定义的ReactorResourceFactory或JettyResourceFactory bean来覆盖Jetty和Reactor Netty的资源配置——这将应用于客户端和服务器。

可以在WebClient Runtime一节中了解更多关于客户端资源配置的信息。

你可能感兴趣的:(SpringBoot学习笔记,spring,boot,java,spring)