3

Spring WebFlux核心处理组件DispatcherHandler

 1 year ago
source link: https://www.51cto.com/article/722032.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Spring WebFlux核心处理组件DispatcherHandler

作者:Spring全家桶实战案例 2022-11-04 08:39:46
DispatcherHandler从Spring配置中发现所需的委托组件。它本身也被设计为bean,并实现ApplicationContextAware以访问它运行的上下文。
e6e68e50946965c9dad50708aa8a47f308a17e.png

​与Spring MVC类似,Spring WebFlux是围绕前端控制器模式设计的,其中核心处理程序WebHandler 的实现DispatcherHandler为请求处理提供共享算法,而实际工作由可配置的委托组件执行。该模型非常灵活,支持多种工作流。

DispatcherHandler从Spring配置中发现所需的委托组件。它本身也被设计为bean,并实现ApplicationContextAware以访问它运行的上下文。如果DispatcherHandler是用webHandler的bean名称声明的,那么WebHttpHandlerBuilder会发现它,它会将请求处理链组合在一起,如webHandler API中所述。

WebFlux应用程序中的Spring配置通常包含:

  1. bean名称为webHandler的DispatcherHandler
  2. WebFilterWebExceptionHandler
  3. DispatcherHandler特殊bean

配置被提供给WebHttpHandlerBuilder以构建处理链,如下例所示:

public class HttpHandlerAutoConfiguration {
  @Configuration(proxyBeanMethods = false)
  public static class AnnotationConfig {
    @Bean
    public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider){
      // applicationContext方法中会收集容器中WebFilter和WebExceptionHandler
      // build方法中构建了HttpWebHandlerAdapter(实现了HttpHandler),该对象中
      // 包装了WebFilter和WebExceptionHandler集合
      HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
      WebFluxProperties properties = propsProvider.getIfAvailable();
      if (properties != null && StringUtils.hasText(properties.getBasePath())) {
        Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);
        return new ContextPathCompositeHandler(handlersMap);
      }
      return httpHandler;
    }
  }
}

特殊一样的Bean

​DispatcherHandler委托特殊bean处理请求并呈现适当的响应。所谓“特殊bean”,是指实现WebFlux框架规定的Spring管理的对象实例。一般都内置这些Bean,不过你可以自定义、扩展或替换它们的属性。

  • HandlerMapping

将请求映射到处理程序。映射基于一些标准,这些标准的细节因HandlerMapping实现的不同而不同——注释控制器、简单URL模式映射等等。如:@RequestMapping注解的Controller或RouterFunction类型的Bean他们都是由不同的HandlerMapping来处理。

  • HandlerAdapter

帮助DispatcherHandler调用映射到请求的处理程序,而不管该处理程序实际是如何调用的。例如,调用带注释的控制器需要解析注释。HandlerAdapter的主要目的是保护DispatcherHandler不受这些细节的影响。简单说就是不同的HandlerAdapter处理由不同HandlerMapping返回的不同的Handler对象,比如:RequestMappingHandlerMapping返回的HandlerMethod,RouterFunctionMapping返回的HandlerFunction。

  • HandlerResultHandler​

处理处理程序调用的结果并完成响应。

WebFlux配置

应用程序可以声明处理请求所需的基础bean(列在Web Handler API和DispatcherHandler下面)。但是,在大多数情况下,WebFlux配置是最好的起点。它声明所需的bean,并提供更高级别的配置回调API来自定义它。

DispatcherHandler处理请求的方式如下:

  • 每个HandlerMapping被要求找到一个匹配的处理程序,并使用第一个匹配。
  • 如果找到处理程序,则通过适当的HandlerAdapter运行它,它将从执行中返回的值公开为HandlerResult
  • HandlerResult被提供给适当的HandlerResultHandler,以通过直接写入响应或使用视图进行渲染来完成处理。

调用处理程序的返回值通过HandlerAdapter被包装为HandlerResult,以及一些附加的上下文,并传递给声称支持它的第一个HandlerResultHandler。下表列出可用的HandlerResultHandler实现,所有这些实现都在WebFlux Config中声明:

  • ResponseEntityResultHandler

返回值:ResponseEntity, 通常来自@Controller实例。

  • ServerResponseResultHandler

返回值:ServerResponse,通常来自功能端点。

  • ResponseBodyResultHandler

返回值:处理来自@ResponseBody方法或@RestController类的返回值。

  • ViewResolutionResultHandler​

返回值:CharSequence、视图、模型、映射、渲染或任何其他对象都被视为模型属性。

从HandlerAdapter返回的HandlerResult可以基于某些特定于处理程序的机制公开用于错误处理的函数。在以下情况下调用此错误函数:

  • 处理程序(例如,@Controller)调用失败。
  • 通过HandlerResultHandler处理处理程序返回值失败。

只要错误信号发生在从处理程序返回的响应类型产生任何数据项之前,error函数就可以更改响应(例如,更改为错误状态)。

这就是如何支持@Controller类中的@ExceptionHandler方法。相比之下,Spring MVC中的支持也是建立在HandlerExceptionResolver上的。注意:在WebFlux中,不能使用@ControllerAdvice来处理在选择处理程序之前发生的异常。​

@RestControllerAdvice
public class PackControllerAdvice {

  @ExceptionHandler
  public ResponseEntity<String> handle(Exception ex){
    ex.printStackTrace();
    return ResponseEntity.ok(ex.getMessage() + ", Advice");
  }

}

注意:这个不能处理调用处理程序之前的任何异常,处理程序之前的异常应该由WebExceptionHandler来处理

下面的异常处理句柄将会处理,由WebFilter实例链和目标WebHandle的异常。

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomWebExceptionHandler implements WebExceptionHandler {

  @Override
  public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
    System.out.println("异常了: " + ex.getMessage()) ;
    // 将错误传递下去,后面的onErrorResume还可以继续执行;如果传递,那么下一个处理器将会是DefaultErrorWebExceptionHandler
    // return Mono.error(ex) ;
    // exchange.getResponse()
    // return Mono.error(ex) ;
    // 下面不传递异常了,直接输出错误信息
    ServerHttpResponse response = exchange.getResponse() ;
    response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR) ;
    response.getHeaders().add("ContentType", "text/html;charset=utf8");
    return response.writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap("ERROR".getBytes(Charset.forName("UTF-8"))))) ;
  }

}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK