0、请求 -> 响应
在 Netty 中,一般会有 2 个 EventLoopGroup。 BossEventLoopGroup 用来监听请求,当收到 ACCEPT 事件时,创建 socket 连接,并将该 socket 注册到 WorkEventLoopGroup 中。WorkEventLoop 监听到 READ 事件时,读取字节流,对请求进行解码,根据请求内容查找对应的处理方法,将结果编码后发送给客户端。
在 WebFlux 中,实现根据请求内容查找对应的处理方法这个过程,是通过HttpHandler
实现的,接口定义如下:
public interface HttpHandler {
/**
* Handle the given request and write to the response.
* @param request current request
* @param response current response
* @return indicates completion of request handling
*/
Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response);
}
以下试着从源码角度,分析HttpHandler
的实现和功能,版本:org.springframework.boot:spring-boot-starter-webflux:2.3.3.RELEASE。
1、HttpHandler
HttpHandler
何时被调用?接收到请求时。
/** NettyWebServer **/
public class NettyWebServer implements WebServer {
private final BiFunction<? super HttpServerRequest, ? super HttpServerResponse, ? extends Publisher<Void>> handler;
private DisposableServer startHttpServer() {
HttpServer server = this.httpServer;
if (this.routeProviders.isEmpty()) {
server = server.handle(this.handler); //1 此时为 HttpServerHandle 类型
}
...
return server.bindNow();
}
/** HttpServerHandle **/
final BiFunction<? super HttpServerRequest, ? super HttpServerResponse, ? extends Publisher<Void>> handler;
public void onStateChange(Connection connection, State newState) {
if (newState == HttpServerState.REQUEST_RECEIVED) { //2 接收到 Request 请求时
try {
HttpServerOperations ops = (HttpServerOperations) connection;
Mono.fromDirect(handler.apply(ops, ops)) //3 执行 HttpHandler
.subscribe(ops.disposeSubscriber());
}
...
}
}
}
在程序启动时,会自动创建一个HttpHandler
bean。
/** HttpHandlerAutoConfiguration **/
public class HttpHandlerAutoConfiguration {
@Configuration(proxyBeanMethods = false)
public static class AnnotationConfig {
@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build(); // 1 创建 HttpHandler
WebFluxProperties properties = propsProvider.getIfAvailable();
// 2 可以设置base-path,类似于springmvc的server.servlet.context-path
if (properties != null && StringUtils.hasText(properties.getBasePath())) {
Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);
return new ContextPathCompositeHandler(handlersMap);
}
return httpHandler;
}
}
}
注意步骤 2,这里可以设置 base-path,类似于 SpringMVC 的 server.servlet.context-path
;
继续分析HttpHandler
的创建过程:
/** WebHttpHandlerBuilder **/
private final WebHandler webHandler;
private final List<WebFilter> filters = new ArrayList<>();
private final List<WebExceptionHandler> exceptionHandlers = new ArrayList<>();
public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {
WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(
context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class), context); //初始化WebHandler
List<WebFilter> webFilters = context
.getBeanProvider(WebFilter.class)
.orderedStream() //排序
.collect(Collectors.toList());
builder.filters(filters -> filters.addAll(webFilters)); //初始化WebFilter
List<WebExceptionHandler> exceptionHandlers = context
.getBeanProvider(WebExceptionHandler.class)
.orderedStream() //排序
.collect(Collectors.toList());
builder.exceptionHandlers(handlers -> handlers.addAll(exceptionHandlers)); //初始化ExceptionHandler
...
return builder;
}
从以上代码分析,HttpHandler
中主要分为三个部分:
- WebFilter:过滤器,类型为 List,所以这是一个过滤器链;
- WebHandler: 请求的业务处理;
- WebExceptionHandler:异常处理。
继续看 build 方法:
/** WebHttpHandlerBuilder **/
public HttpHandler build() {
WebHandler decorated = new FilteringWebHandler(this.webHandler, this.filters);
decorated = new ExceptionHandlingWebHandler(decorated, this.exceptionHandlers);
HttpWebHandlerAdapter adapted = new HttpWebHandlerAdapter(decorated);
...
if (this.applicationContext != null) {
adapted.setApplicationContext(this.applicationContext);
}
adapted.afterPropertiesSet();
return adapted;
}
最终生成的HttpHandler
是HttpWebHandlerAdapter
类型,并且其 delegate 为ExceptionHandlingWebHandler
,其 delegate 为FilteringWebHandler
,其 delegate 为this.webHandler
。构成了下面的调用链:
HttpWebHandlerAdapter
-> ExceptionHandlingWebHandler
-> FilteringWebHandler
-> this.webHandler
。
/** HttpWebHandlerAdapter **/
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
...
return getDelegate().handle(exchange) //调用ExceptionHandlingWebHandler的handle
.doOnSuccess(aVoid -> logResponse(exchange))
.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
.then(Mono.defer(response::setComplete));
}
/** ExceptionHandlingWebHandler **/
public Mono<Void> handle(ServerWebExchange exchange) {
Mono<Void> completion;
try {
completion = super.handle(exchange); //调用FilteringWebHandler的handle
}
catch (Throwable ex) {
completion = Mono.error(ex);
}
for (WebExceptionHandler handler : this.exceptionHandlers) { //如果报异常,处理异常
completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));
}
return completion;
}
/** FilteringWebHandler **/
public class FilteringWebHandler extends WebHandlerDecorator {
private final DefaultWebFilterChain chain;
public FilteringWebHandler(WebHandler handler, List<WebFilter> filters) {
super(handler);
this.chain = new DefaultWebFilterChain(handler, filters);
}
public List<WebFilter> getFilters() {
return this.chain.getFilters();
}
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
return this.chain.filter(exchange); //调用DefaultWebFilterChain的filter
}
}
/** DefaultWebFilterChain **/
private static DefaultWebFilterChain initChain(List<WebFilter> filters, WebHandler handler) {
DefaultWebFilterChain chain = new DefaultWebFilterChain(filters, handler, null, null);
ListIterator<? extends WebFilter> iterator = filters.listIterator(filters.size());
// 这里实现了:当执行 chain.filter(exchange) 时,会调用下一个 webfilter
while (iterator.hasPrevious()) {
chain = new DefaultWebFilterChain(filters, handler, iterator.previous(), chain);
}
return chain;
}
public Mono<Void> filter(ServerWebExchange exchange) {
// 当执行完 webfilter 后,开始执行 webhandler
return Mono.defer(() ->
this.currentFilter != null && this.chain != null ?
invokeFilter(this.currentFilter, this.chain, exchange) :
this.handler.handle(exchange));
}
private Mono<Void> invokeFilter(WebFilter current, DefaultWebFilterChain chain, ServerWebExchange exchange) {
String currentName = current.getClass().getName();
return current.filter(exchange, chain).checkpoint(currentName + " [DefaultWebFilterChain]");
}
针对以上代码实现的功能,可以用一张图来表示:
其中,黑线表示请求的正常过程,红线表示发生异常后的处理过程。
2、WebFilter
以一个简单的 demo 来看WebFilter
的使用:
/** Log1Filter **/
@Component
@Order(100)
public class Log1Filter implements WebFilter {
private static final Logger logger = LoggerFactory.getLogger(Log1Filter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
logger.info("left: 111");
return chain.filter(exchange)
.doOnSuccess(aVoid -> logger.info("right: 111"))
.doOnError(RuntimeException.class, e -> logger.error("error1: {}", e.getMessage()));
}
}
/** Log2Filter **/
@Component
@Order(200)
public class Log2Filter implements WebFilter {
private static final Logger logger = LoggerFactory.getLogger(Log2Filter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
logger.info("left: 222");
return chain.filter(exchange)
.doOnSuccess(aVoid -> logger.info("right: 222"))
.doOnError(RuntimeException.class, e -> logger.error("error2: {}", e.getMessage()));
}
}
@RestController
@RequestMapping("/testfilter")
public class TestFilterController {
private static final Logger logger = LoggerFactory.getLogger(TestFilterController.class);
@GetMapping("/test-ok")
public Mono<String> testOk(@RequestParam("name") String name) {
logger.info("get name: {}", name);
return Mono.just(name);
}
@GetMapping("/test-error")
public Mono<String> testError(@RequestParam("name") String name) {
logger.info("get name: {}", name);
throw new RuntimeException("get name error");
}
}
调用 test-ok 接口返回:
2020-08-23 16:51:15.749 INFO 50589 --- [ctor-http-nio-2] m.p.demos.webflux.filter.Log1Filter : left: 111
2020-08-23 16:51:15.751 INFO 50589 --- [ctor-http-nio-2] m.p.demos.webflux.filter.Log2Filter : left: 222
2020-08-23 16:51:15.778 INFO 50589 --- [ctor-http-nio-2] m.p.d.w.controller.TestFilterController : invoke method: testOk
2020-08-23 16:51:15.799 INFO 50589 --- [ctor-http-nio-2] m.p.demos.webflux.filter.Log2Filter : right: 222
2020-08-23 16:51:15.799 INFO 50589 --- [ctor-http-nio-2] m.p.demos.webflux.filter.Log1Filter : right: 111
调用 test-error 接口返回:
2020-08-23 16:51:18.909 INFO 50589 --- [ctor-http-nio-2] m.p.demos.webflux.filter.Log1Filter : left: 111
2020-08-23 16:51:18.910 INFO 50589 --- [ctor-http-nio-2] m.p.demos.webflux.filter.Log2Filter : left: 222
2020-08-23 16:51:18.911 INFO 50589 --- [ctor-http-nio-2] m.p.d.w.controller.TestFilterController : invoke method: testError
2020-08-23 16:51:18.920 ERROR 50589 --- [ctor-http-nio-2] m.p.demos.webflux.filter.Log2Filter : error2: error
2020-08-23 16:51:18.928 ERROR 50589 --- [ctor-http-nio-2] m.p.demos.webflux.filter.Log1Filter : error1: error
2020-08-23 16:51:18.966 ERROR 50589 --- [ctor-http-nio-2] a.w.r.e.AbstractErrorWebExceptionHandler : [5b86a385-2] 500 Server Error for HTTP GET "/testfilter/test-error"
3、WebHandler
(DispatcherHandler
)
默认的WebHandler
是DispatcherHandler
。
/** WebFluxConfigurationSupport **/
public class WebFluxConfigurationSupport implements ApplicationContextAware {
@Bean
public DispatcherHandler webHandler() {
return new DispatcherHandler();
}
}
看下实现:
/** DispatcherHandler **/
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
private List<HandlerMapping> handlerMappings;
private List<HandlerAdapter> handlerAdapters;
private List<HandlerResultHandler> resultHandlers;
protected void initStrategies(ApplicationContext context) {
Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerMapping.class, true, false);
ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
AnnotationAwareOrderComparator.sort(mappings);
this.handlerMappings = Collections.unmodifiableList(mappings);
Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerAdapter.class, true, false);
this.handlerAdapters = new ArrayList<>(adapterBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerResultHandler.class, true, false);
this.resultHandlers = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(this.resultHandlers);
}
}
DispatcherHandler
中也主要分为三部分:
HandlerMapping
:根据 http 请求,找到对应的处理方法。比如根据 URL 和 HttpMethod,确定对应的 Controller 层的某个方法。HandlerAdapter
:调用具体的处理方法;HandlerResultHandler
:针对返回类型,进行不同的处理,并发送给客户端;
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next() //找到第一个可用的handler
.switchIfEmpty(createNotFoundError())
.flatMap(handler -> invokeHandler(exchange, handler)) //处理请求
.flatMap(result -> handleResult(exchange, result)); //处理结果
}
3.1 HandlerMapping
其接口定义如下:
/** HandlerMapping **/
public interface HandlerMapping {
Mono<Object> getHandler(ServerWebExchange exchange);
}
/** AbstractHandlerMapping **/
public Mono<Object> getHandler(ServerWebExchange exchange) {
return getHandlerInternal(exchange).map(handler -> {
...
return handler;
});
}
列举几种常见的HandlerMapping
:
RouterFunctionMapping
: 处理RouterFunction
接口定义的请求路由;
RequestMappingHandlerMapping
: 处理@Controller
以及@RequestMapping
定义的请求路由;
SimpleUrlHandlerMapping
: 处理基于 url 的请求路由;
这里需要注意的是,对于同一个请求,有可能会找到多个路由;因此这些路由需要有个优先级,一旦找到匹配的路由,就不会查询后续的路由了。
/** WebFluxConfigurationSupport **/
public class WebFluxConfigurationSupport implements ApplicationContextAware {
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
...
return mapping;
}
@Bean
public RouterFunctionMapping routerFunctionMapping(ServerCodecConfigurer serverCodecConfigurer) {
RouterFunctionMapping mapping = createRouterFunctionMapping();
mapping.setOrder(-1); // go before RequestMappingHandlerMapping
mapping.setMessageReaders(serverCodecConfigurer.getReaders());
mapping.setCorsConfigurations(getCorsConfigurations());
return mapping;
}
}
从以上代码可知,RouterFunctionMapping
的优先级要高于RequestMappingHandlerMapping
。
写段代码验证一下:
@RestController
@RequestMapping("/testrouter")
public class UrlRouterFunction implements RouterFunction {
@GetMapping("/test")
public Mono<String> test() {
return Mono.just("RequestMappingHandlerMapping");
}
@Override
public Mono<HandlerFunction> route(ServerRequest request) {
HandlerFunction urlHandler = req -> ServerResponse.ok().bodyValue("RouterFunctionMapping");
if (request.uri().getPath().equals("/testrouter/test")) {
return Mono.defer(() -> Mono.just(urlHandler));
} else {
return Mono.empty();
}
}
}
调用请求:
➜ ~ curl -L -X GET 'http://127.0.0.1:8080/testrouter/test';
RouterFunctionMapping
3.2 HandlerAdapter
其接口定义如下:
public interface HandlerAdapter {
/**
* Whether this {@code HandlerAdapter} supports the given {@code handler}.
* @param handler the handler object to check
* @return whether or not the handler is supported
*/
boolean supports(Object handler);
/**
* Handle the request with the given handler.
* <p>Implementations are encouraged to handle exceptions resulting from the
* invocation of a handler in order and if necessary to return an alternate
* result that represents an error response.
* <p>Furthermore since an async {@code HandlerResult} may produce an error
* later during result handling implementations are also encouraged to
* {@link HandlerResult#setExceptionHandler(Function) set an exception
* handler} on the {@code HandlerResult} so that may also be applied later
* after result handling.
* @param exchange current server exchange
* @param handler the selected handler which must have been previously
* checked via {@link #supports(Object)}
* @return {@link Mono} that emits a single {@code HandlerResult} or none if
* the request has been fully handled and doesn't require further handling.
*/
Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler);
}
HandlerAdapter.supports()
方法的主要作用在于判断当前的HandlerAdapter
是否能够支持传过来的 handler。以RequestMappingHandlerAdapter
为例,
public class RequestMappingHandlerAdapter implements HandlerAdapter, ApplicationContextAware, InitializingBean {
public boolean supports(Object handler) { //支持HandlerMethod类型
return handler instanceof HandlerMethod;
}
@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
InitBinderBindingContext bindingContext = new InitBinderBindingContext(
getWebBindingInitializer(), this.methodResolver.getInitBinderMethods(handlerMethod));
InvocableHandlerMethod invocableMethod = this.methodResolver.getRequestMappingMethod(handlerMethod);
Function<Throwable, Mono<HandlerResult>> exceptionHandler =
ex -> handleException(ex, handlerMethod, bindingContext, exchange);
return this.modelInitializer
.initModel(handlerMethod, bindingContext, exchange)
.then(Mono.defer(() -> invocableMethod.invoke(exchange, bindingContext))) //通过反射调用具体的方法
.doOnNext(result -> result.setExceptionHandler(exceptionHandler))
.doOnNext(result -> bindingContext.saveModel())
.onErrorResume(exceptionHandler); //处理`@ExceptionHandler`指定的异常
}
}
3.3 HandlerResultHandler
其接口定义如下:
public interface HandlerResultHandler {
/**
* Whether this handler supports the given {@link HandlerResult}.
* @param result the result object to check
* @return whether or not this object can use the given result
*/
boolean supports(HandlerResult result);
/**
* Process the given result modifying response headers and/or writing data
* to the response.
* @param exchange current server exchange
* @param result the result from the handling
* @return {@code Mono<Void>} to indicate when request handling is complete.
*/
Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result);
}
以ResponseBodyResultHandler
为例,可以处理通过@ResponseBody
标识的方法:
public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandler implements HandlerResultHandler {
@Override
public boolean supports(HandlerResult result) {
MethodParameter returnType = result.getReturnTypeSource();
Class<?> containingClass = returnType.getContainingClass();
// 支持@ResponseBody注解
return (AnnotatedElementUtils.hasAnnotation(containingClass, ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
@Override
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
Object body = result.getReturnValue();
MethodParameter bodyTypeParameter = result.getReturnTypeSource();
return writeBody(body, bodyTypeParameter, exchange);
}
}
继续分析对结果进行了哪些处理:
public abstract class AbstractMessageWriterResultHandler extends HandlerResultHandlerSupport {
protected Mono<Void> writeBody(@Nullable Object body, MethodParameter bodyParameter,
@Nullable MethodParameter actualParam, ServerWebExchange exchange) {
ResolvableType bodyType = ResolvableType.forMethodParameter(bodyParameter); //返回类型,比如MonoJust
ResolvableType actualType = (actualParam != null ? ResolvableType.forMethodParameter(actualParam) : bodyType);
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(bodyType.resolve(), body); //适配器
Publisher<?> publisher;
ResolvableType elementType;
ResolvableType actualElementType; //实际类型,如果通过适配器封装过,获取封装前的类型
if (adapter != null) {
publisher = adapter.toPublisher(body);
boolean isUnwrapped = KotlinDetector.isKotlinReflectPresent() &&
KotlinDetector.isKotlinType(bodyParameter.getContainingClass()) &&
KotlinDelegate.isSuspend(bodyParameter.getMethod()) &&
!COROUTINES_FLOW_CLASS_NAME.equals(bodyType.toClass().getName());
ResolvableType genericType = isUnwrapped ? bodyType : bodyType.getGeneric();
elementType = getElementType(adapter, genericType);
actualElementType = elementType;
}
else {
publisher = Mono.justOrEmpty(body);
actualElementType = body != null ? ResolvableType.forInstance(body) : bodyType;
elementType = (bodyType.toClass() == Object.class && body != null ? actualElementType : bodyType);
}
if (elementType.resolve() == void.class || elementType.resolve() == Void.class) {
return Mono.from((Publisher<Void>) publisher);
}
//选择最佳的MediaType
MediaType bestMediaType = selectMediaType(exchange, () -> getMediaTypesFor(elementType));
if (bestMediaType != null) {
String logPrefix = exchange.getLogPrefix();
...
//遍历HttpMessageWriter,找到第一个可以处理该对象类型的writer,编码后响应给客户端
for (HttpMessageWriter<?> writer : getMessageWriters()) {
if (writer.canWrite(actualElementType, bestMediaType)) {
return writer.write((Publisher) publisher, actualType, elementType,
bestMediaType, exchange.getRequest(), exchange.getResponse(),
Hints.from(Hints.LOG_PREFIX_HINT, logPrefix));
}
}
}
...
}
}
分析以上代码,发现前面的大部分代码是用于确定返回的对象类型、计算MediaType
等,关键的部分是选择第一个可以处理返回对象类型的HttpMessageWriter
,然后发送响应。
看下HttpMessageWriter
定义:
public interface HttpMessageWriter<T> {
/**
* Return the {@link MediaType}'s that this writer supports.
* 支持哪些MediaType
*/
List<MediaType> getWritableMediaTypes();
/**
* Whether the given object type is supported by this writer.
* @param elementType the type of object to check
* @param mediaType the media type for the write (possibly {@code null})
* @return {@code true} if writable, {@code false} otherwise
* 是否支持给定的对象类型
*/
boolean canWrite(ResolvableType elementType, @Nullable MediaType mediaType);
/**
* Write an given stream of object to the output message.
* @param inputStream the objects to write
* @param elementType the type of objects in the stream which must have been
* previously checked via {@link #canWrite(ResolvableType, MediaType)}
* @param mediaType the content type for the write (possibly {@code null} to
* indicate that the default content type of the writer must be used)
* @param message the message to write to
* @param hints additional information about how to encode and write
* @return indicates completion or error
* 发送响应
*/
Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType elementType,
@Nullable MediaType mediaType, ReactiveHttpOutputMessage message, Map<String, Object> hints);
/**
* Server-side only alternative to
* {@link #write(Publisher, ResolvableType, MediaType, ReactiveHttpOutputMessage, Map)}
* with additional context available.
* @param actualType the actual return type of the method that returned the
* value; for annotated controllers, the {@link MethodParameter} can be
* accessed via {@link ResolvableType#getSource()}.
* @param elementType the type of Objects in the input stream
* @param mediaType the content type to use (possibly {@code null} indicating
* the default content type of the writer should be used)
* @param request the current request
* @param response the current response
* @return a {@link Mono} that indicates completion of writing or error
*/
default Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType actualType,
ResolvableType elementType, @Nullable MediaType mediaType, ServerHttpRequest request,
ServerHttpResponse response, Map<String, Object> hints) {
return write(inputStream, elementType, mediaType, response, hints);
}
}
debug 看下getMessageWriters()
返回了哪些 MessageWriter:
如果返回 byte[] 类型,会选择ByteArrayEncoder
编码;如果返回 String 类型并且 MediaType 为 text/plain,会选择CharSequenceEncoder
编码;JSON 会选择Jackson2JsonEncoder
编码等。
4、WebExceptionHandler
WebExceptionHandler
主要用来处理异常。但是如果对异常指定了@ExceptionHandler
注解的话,实际处理过程在RequestMappingHandlerAdapter
中,具体见RequestMappingHandlerAdapter
的handleException
方法。
先看下接口定义:
public interface WebExceptionHandler {
/**
* Handle the given exception. A completion signal through the return value
* indicates error handling is complete while an error signal indicates the
* exception is still not handled.
* @param exchange the current exchange
* @param ex the exception to handle
* @return {@code Mono<Void>} to indicate when exception handling is complete
*/
Mono<Void> handle(ServerWebExchange exchange, Throwable ex);
}
实现该接口的默认 bean 有两个:DefaultErrorWebExceptionHandler
以及WebFluxResponseStatusExceptionHandler
,前者的 order 更小,并且处理完异常后会发送给请求方,所以主要看下前者。
public class ErrorWebFluxAutoConfiguration {
@Bean
@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT)
@Order(-1)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes,
ResourceProperties resourceProperties, ObjectProvider<ViewResolver> viewResolvers,
ServerCodecConfigurer serverCodecConfigurer, ApplicationContext applicationContext) {
DefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(errorAttributes,
resourceProperties, this.serverProperties.getError(), applicationContext);
exceptionHandler.setViewResolvers(viewResolvers.orderedStream().collect(Collectors.toList()));
exceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());
return exceptionHandler;
}
}
如果需要自定义全局异常,可以自定义一个ErrorWebExceptionHandler
bean。这部分内容网上比较多,就不重复了。