美文网首页
SpringCloud升级之路2020.0.x版-41. Spr

SpringCloud升级之路2020.0.x版-41. Spr

作者: 干货满满张哈希 | 来源:发表于2021-11-25 23:19 被阅读0次
    image

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent

    我们继续分析上一节提到的 WebHandler,经过将请求封装成 ServerWebExchange 的 HttpWebHandlerAdapter 之后,请求会经过 ExceptionHandlingWebHandler

    image

    全局 Web 处理异常处理器的接入点 - ExceptionHandlingWebHandler

    之前有网友私信问过笔者,如何给 Spring Cloud Gateway 加全局异常处理器,其实和给基于 Spring-Flux 的异步 Web 服务加是一样的,都是通过实现并注册一个 WebExceptionHandler Bean

    WebExceptionHandler.java

    public interface WebExceptionHandler {
        Mono<Void> handle(ServerWebExchange exchange, Throwable ex);
    }
    

    这些 Bean,就是在 ExceptionHandlingWebHandler 被加入到整个请求处理链路中的:

    ExceptionHandlingWebHandler.java

    @Override
    public Mono<Void> handle(ServerWebExchange exchange) {
        Mono<Void> completion;
        try {
            //这里其实就是组装后面的链路,即调用后面的 FilteringWebHandler 的 handle
            completion = super.handle(exchange);
        }
        catch (Throwable ex) {
            completion = Mono.error(ex);
        }
    
        for (WebExceptionHandler handler : this.exceptionHandlers) {
            completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));
        }
        return completion;
    }
    

    从源码可以看出,这里将每个 WebExceptionHandler 作为 Mono 的异常处理 onErrorResume 加入了链路。onErrorResume 的意思是如果链路前面发生异常,则在这里捕获住异常同时调用 handler.handle(exchange, ex) 进行处理,如果使用阻塞代码理解,就相当于:

    try {
        //前面的链路
    } catch(Throwable ex) {
        return handler.handle(exchange, ex)
    }
    

    这里我们看到有多个 WebExceptionHandler,都会在链路后面追加 onErrorResume,其实就相当于:

    completion.onErrorResume(ex -> webExceptionHandler1.handle(exchange, ex)).onErrorResume(ex -> webExceptionHandler2.handle(exchange, ex)).onErrorResume(ex -> webExceptionHandler3.handle(exchange, ex))...
    

    转换成阻塞代码理解,其实就是:

    try {
        completion
    } catch(Throwable e1) {
        try {
            return webExceptionHandler1.handle(exchange, e1)
        } catch(Throwable e2) {
            try {
                return webExceptionHandler2.handle(exchange, ex)
            } catch(Throwable e2) {
                return webExceptionHandler3.handle(exchange, ex)
                //如果还有就继续叠加
            }
        }
    }
    

    当 WebExceptionHandler 可以处理这个异常的时候,他的 handle 方法会返回一个真正的响应,否则会返回异常,例如:

    public class WebExceptionHandler1 implements WebExceptionHandler {
        @Override
        public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
            //如果是 ResponseStatusException 则使用异常里面的响应码和 HTTP 头填充响应的响应码和 HTTP 头
            if (ex instanceof ResponseStatusException) {
                ServerHttpResponse response = exchange.getResponse();
                ResponseStatusException responseStatusException = (ResponseStatusException) ex;
                response.setRawStatusCode(responseStatusException.getRawStatusCode());
                responseStatusException.getResponseHeaders()
                        .forEach((name, values) ->
                                values.forEach(value -> response.getHeaders().add(name, value)));
                //返回响应完成
                return response.setComplete();
            }
            //抛出异常,继续链路异常处理
            return Mono.error(ex);
        }
    }
    

    转换成同步代码去理解其实就是:

    if (ex instanceof ResponseStatusException) {
        ServerHttpResponse response = exchange.getResponse();
        ResponseStatusException responseStatusException = (ResponseStatusException) ex;
        response.setRawStatusCode(responseStatusException.getRawStatusCode());
        responseStatusException.getResponseHeaders()
                .forEach((name, values) ->
                        values.forEach(value -> response.getHeaders().add(name, value)));
        //返回响应完成
        return response.setComplete();
    }
    //抛出异常,继续链路异常处理
    throw ex;
    

    如果大家想封装自己统一的错误响应,可以通过实现这个接口进行实现。

    DefaultWebFilterChain 的链路起点 - FilteringWebHandler

    接下来进入 FilteringWebHandler,注意是 org.springframework.web.server.handler.FilteringWebHandler 而不是 Spring Cloud Gateway 的 org.springframework.cloud.gateway.handler.FilteringWebHandler。在这里,会将上下文中载入的 WebFilter 拼接成 DefaultWebFilterChain,然后调用其 filter 方法:

    private final DefaultWebFilterChain chain;
    
    public FilteringWebHandler(WebHandler handler, List<WebFilter> filters) {
        super(handler);
        this.chain = new DefaultWebFilterChain(handler, filters);
    }
    
    @Override
    public Mono<Void> handle(ServerWebExchange exchange) {
        return this.chain.filter(exchange);
    }
    

    Spring Cloud Gateway 的 FilteringWebHandler, 它是 Spring Cloud Gateway 的处理请求业务的起点。在这里我们即将进入整个 Spring Cloud Gateway 的 Filter 链路,包括每个路径自己的 GatewayFilter 以及全局的 GlobalGatewayFilter,都是在这里开始被处理组装成完整调用链路的。我们后面还会提到

    由于我们的项目依赖中包含了 Spring Cloud Sleuth 以及 Prometheus 的依赖,所以我们这里的 WebFilter 会包括三个:

    • org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter:添加 Prometheus 相关依赖之后,会有这个 MetricsWebFilter,用于记录请求处理耗时,采集相关指标。
    • org.springframework.cloud.sleuth.instrument.web.TraceWebFilter:添加 Spring Cloud Sleuth 相关依赖之后,会有这个 TraceWebFilter。
    • org.springframework.cloud.gateway.handler.predicate.WeightCalculatorWebFilter:Spring Cloud Gateway 路由权重相关配置功能相关实现类,这个我们这里不关心。

    其具体流程,我们在下一节中继续详细分析。

    相关文章

      网友评论

          本文标题:SpringCloud升级之路2020.0.x版-41. Spr

          本文链接:https://www.haomeiwen.com/subject/elftxrtx.html