Spring WebFlux核心处理组件DispatcherHandler

开发 架构
DispatcherHandler从Spring配置中发现所需的委托组件。它本身也被设计为bean,并实现ApplicationContextAware以访问它运行的上下文。

概述

​与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
  4. 其它

配置被提供给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"))))) ;
}

}
责任编辑:姜华 来源: 今日头条
相关推荐

2023-02-09 08:01:12

核心组件非阻塞

2022-07-04 09:15:10

Spring请求处理流程

2020-05-21 13:25:43

Spring组件架构

2023-09-04 11:52:53

SpringMVC性能

2022-01-05 08:53:13

Spring原理分析MVC

2023-11-02 18:01:24

SpringMVC配置

2020-07-07 07:00:00

Spring WebFREST APIReactive AP

2019-03-04 08:48:23

Spring WebFJavaIO

2020-03-24 09:54:57

SpringMVCWebFlux

2024-03-06 07:52:21

Spring框架响应式编程微服务架构

2022-09-26 08:54:39

Spring函数式编程

2021-07-15 11:16:31

Spring WebWebFlux架构

2019-08-06 09:21:45

2020-05-25 07:00:00

双因素认证身份认证密码

2024-01-10 09:59:19

虚拟线程信息

2009-07-17 12:54:13

2023-02-23 08:15:33

Spring异常处理机制

2011-04-22 10:13:35

SimpleFrame

2021-02-19 08:38:36

Kubernetes容器化分布式

2022-09-30 10:44:47

Netty组件数据
点赞
收藏

51CTO技术栈公众号