【深入解析spring cloud gateway】06 gateway源码简要分析

这篇具有很好参考价值的文章主要介绍了【深入解析spring cloud gateway】06 gateway源码简要分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

上一节做了一个很简单的示例,微服务通过注册到eureka上,然后网关通过服务发现访问到对应的微服务。本节将简单地对整个gateway请求转发过程做一个简单的分析。

一、核心流程

【深入解析spring cloud gateway】06 gateway源码简要分析,深入解析析SpringCloud Gateway,gateway

主要流程:

  • Gateway Client向 Spring Cloud Gateway 发送请求
  • 请求首先会被HttpWebHandlerAdapter 进行提取组装成网关上下文
  • 然后网关的上下文会传递到DispatcherHandler ,它负责将请求分发给 RoutePredicateHandlerMapping
  • RoutePredicateHandlerMapping负责路由查找,并根据路由断言判断路由是否可用
  • 如果过断言成功,由FilteringWebHandler 创建过滤器链并调用
  • 通过特定于请求的 Fliter 链运行请求,Filter 被虚线分隔的原因是Filter可以在发送代理请求之前(pre)和之后(post)运行逻辑
  • 执行所有pre过滤器逻辑。然后进行代理请求。发出代理请求后,将运行“post”过滤器逻辑。
  • 处理完毕之后将 Response 返回到 Gateway 客户端

二、具体分析

请求过来,会经过HttpWebHandlerAdapter.handle方法,可以理解为这就是请求的主入口

@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
    if (this.forwardedHeaderTransformer != null) {
        try {
            request = this.forwardedHeaderTransformer.apply(request);
        }
        catch (Throwable ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to apply forwarded headers to " + formatRequest(request), ex);
            }
            response.setStatusCode(HttpStatus.BAD_REQUEST);
            return response.setComplete();
        }
    }
 //组装上下文
    ServerWebExchange exchange = createExchange(request, response);

    LogFormatUtils.traceDebug(logger, traceOn ->
            exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
                    (traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));
//委派给delegate来处理
    return getDelegate().handle(exchange)
            .doOnSuccess(aVoid -> logResponse(exchange))
            .onErrorResume(ex -> handleUnresolvedError(exchange, ex))
            .then(Mono.defer(response::setComplete));
}

这一个delegate是个啥,看一下接口定义:
就是一个处理器,所有参数封装在上下文exchange中

public interface WebHandler {

    /**
     * Handle the web server exchange.
     * @param exchange the current server exchange
     * @return {@code Mono<Void>} to indicate when request handling is complete
     */
    Mono<Void> handle(ServerWebExchange exchange);

}

最终会调到DispatcherHandler

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
    if (this.handlerMappings == null) {
        return createNotFoundError();
    }
    if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
        return handlePreFlight(exchange);
    }
    return Flux.fromIterable(this.handlerMappings)
            .concatMap(mapping -> mapping.getHandler(exchange))
            .next()
            .switchIfEmpty(createNotFoundError())
            .flatMap(handler -> invokeHandler(exchange, handler))
            .flatMap(result -> handleResult(exchange, result));
}

handlerMappings是啥
是一个列表,HandlerMapping可以根据当前请求,找到对应的处理器
如果当前请求比如/hello/world,在gateway服务上是一个controller对应的接口,那这个就可以通过RequestMappingHandlerMapping找到一个RequestMappingHandlerAdapter。
如果当前请求,是需要转发给下游微服务的,则找到RoutePredicateHandlerMapping
【深入解析spring cloud gateway】06 gateway源码简要分析,深入解析析SpringCloud Gateway,gateway
RoutePredicateHandlerMapping查找路由主要逻辑

@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
    // don't handle requests on management port if set and different than server port
    if (this.managementPortType == DIFFERENT && this.managementPort != null
            && exchange.getRequest().getLocalAddress() != null
            && exchange.getRequest().getLocalAddress().getPort() == this.managementPort) {
        return Mono.empty();
    }
    exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());

    return lookupRoute(exchange)
            // .log("route-predicate-handler-mapping", Level.FINER) //name this
            .flatMap((Function<Route, Mono<?>>) r -> {
                exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
                if (logger.isDebugEnabled()) {
                    logger.debug("Mapping [" + getExchangeDesc(exchange) + "] to " + r);
                }
                                //把找到的路由放到exchange上下文中
                exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
                                //返回的handler实际上是webHandler
                return Mono.just(webHandler);
            }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
                exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
                if (logger.isTraceEnabled()) {
                    logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]");
                }
            })));
}

看下查找路由的具体方式:原来是将所有的路由,用predicate作一下匹配,找出符合当前请求的路由

protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
    return this.routeLocator.getRoutes()
            // individually filter routes so that filterWhen error delaying is not a
            // problem
            .concatMap(route -> Mono.just(route).filterWhen(r -> {
                // add the current route we are testing
                exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
                //用predicate作一下匹配,找出符合当前请求的路由
                        return r.getPredicate().apply(exchange);
            })
                    // instead of immediately stopping main flux due to error, log and
                    // swallow it
                    .doOnError(e -> logger.error("Error applying predicate for route: " + route.getId(), e))
                    .onErrorResume(e -> Mono.empty()))
            // .defaultIfEmpty() put a static Route not found
            // or .switchIfEmpty()
            // .switchIfEmpty(Mono.<Route>empty().log("noroute"))
            .next()
            // TODO: error handling
            .map(route -> {
                if (logger.isDebugEnabled()) {
                    logger.debug("Route matched: " + route.getId());
                }
                validateRoute(route, exchange);
                return route;
            });

    /*
     * TODO: trace logging if (logger.isTraceEnabled()) {
     * logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
     */
}

routeLocator包含了哪些路由,Debug看一下
【深入解析spring cloud gateway】06 gateway源码简要分析,深入解析析SpringCloud Gateway,gateway

可以看到,用了服务注册和发现后,实际上,一个微服务会自动注册一个路由,比如上面的hello-service,自动注册了一个路径为:/hello-service/**的路由。这就是为什么我们yml配置文件中明明什么路由也没有配置,也能自动转发hello-service的请求。
同时,可以看到,这个路由下面有一个ReWritePathFilter,会自动去掉服务名,将请求转发给下游微服务。
【深入解析spring cloud gateway】06 gateway源码简要分析,深入解析析SpringCloud Gateway,gateway

下一步再看看FilteringWebHandler中的处理逻辑

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
//从上下文中取出路由,路由中包含filters
    Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
    List<GatewayFilter> gatewayFilters = route.getFilters();
//spring容器中的Global Filter也取出来
    List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
    combined.addAll(gatewayFilters);
    // TODO: needed or cached?
 //做个排序
    AnnotationAwareOrderComparator.sort(combined);

    if (logger.isDebugEnabled()) {
        logger.debug("Sorted gatewayFilterFactories: " + combined);
    }
//后面就是filter链式调用了
    return new DefaultGatewayFilterChain(combined).filter(exchange);
}

可以看到代码中主要有两个逻辑:
1、从上下文中取出路由,路由中包含filters
2、spring容器中的Global Filter也取出来
3、合并上面的两种filter,并且排序
4、filters列表组装成责任链来进行调用
可以通过源码,再来看看核心流程的那个图,这样就比较清楚了。
总结了另一个稍微详细一点的图:
【深入解析spring cloud gateway】06 gateway源码简要分析,深入解析析SpringCloud Gateway,gateway

个人看这块源码的体会:整个核心流程并不复杂,难点大概是reactor响应式编程,如果之前没接触过这一块,那么看着会有种不知道下一步往哪里的困惑!所以要学习这块源码,还得学习reactor。文章来源地址https://www.toymoban.com/news/detail-695942.html

到了这里,关于【深入解析spring cloud gateway】06 gateway源码简要分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【深入解析spring cloud gateway】08 Reactor 知识扫盲

    1.1 背景知识 为了应对高并发服务器端开发场景,在2009 年,微软提出了一个更优雅地实现异步编程的方式——Reactive Programming,我们称之为响应式编程。随后,Netflix 和LightBend 公司提供了RxJava 和Akka Stream 等技术,使得Java 平台也有了能够实现响应式编程的框架。 在2017 年9 月

    2024年02月09日
    浏览(38)
  • 【深入解析spring cloud gateway】07 自定义异常返回报文

    Servlet的HttpResponse对象,返回响应报文,一般是这么写的,通过输出流直接就可以将返回报文输出。 在filter中如果发生异常(例如请求参数不合法),抛出异常信息的时候,调用方收到的返回码和body都是Spring Cloud Gateway框架处理来处理的。这一节我们分析一下,gateway的异常返

    2024年02月10日
    浏览(34)
  • 【源码】Spring Cloud Gateway 是在哪里匹配路由的?

    我们知道,经过网关的业务请求会被路由到后端真实的业务服务上去,假如我们使用的是Spring Cloud Gateway,那么你知道Spring Cloud Gateway是在哪一步去匹配路由的吗? 源码之下无秘密,让我们一起从源码中寻找答案。 Spring Cloud Gateway 的入口为 DispatcherHandler 的 handle 方法,其中主

    2023年04月24日
    浏览(38)
  • Spring Cloud - 手写 Gateway 源码,实现自定义局部 FilterFactory

    目录 一、FilterFactory 分析 1.1、前置知识 1.2、分析源码 1.2.1、整体分析 1.2.2、源码分析 1.3、手写源码 1.3.1、基础框架 1.3.2、实现自定义局部过滤器 1.3.3、加参数的自定义局部过滤器器 前面的学习我们知道,GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服

    2024年02月03日
    浏览(42)
  • 细到不能再细的 Spring Cloud Gateway 原理分析(内含多张图片讲解)

    本文会通过图文的方式由浅入深的描述 Spring Cloud Gateway (以下简称 gateway)的基本原理。 本文不涉及 gateway 的任何示例代码, 如有需要请参考官网 sample 。 阅读前, 需要读者提前掌握 gateway 的基本使用。至少要能读懂如下配置的含义: 一、Gateway 在微服务中的作用 当 请求方

    2023年04月09日
    浏览(58)
  • 【Spring Cloud】深入探索统一网关 Gateway 的搭建,断言工厂,过滤器工厂,全局过滤器以及跨域问题

    在微服务架构中,网关是至关重要的组件,具有多重职责,为整个系统提供了一系列关键功能。从下面的微服务结构图中,我们可以明确网关的几项主要作用: 微服务结构图: 请求过滤与安全: 用户的所有请求首先经过网关,这使得网关成为系统的第一道防线。通过对传入

    2024年02月07日
    浏览(57)
  • 云原生之深入解析K8S Istio Gateway服务的架构分析与实战操作

    Istio 提供一种简单的方式来为已部署的服务建立网络,该网络具有负载均衡、服务间认证、监控、网关等功能,而不需要对服务的代码做任何改动。 istio 适用于容器或虚拟机环境(特别是 k8s),兼容异构架构; istio 使用 sidecar(边车模式)代理服务的网络,不需要对业务代

    2024年02月13日
    浏览(59)
  • 【深入Spring源码解析:解密Bean的生命周期】

    Spring是Java企业级应用开发领域的一颗明星,它提供了很多方便开发人员的工具和思想。在分布式系统中,Spring的分布式远程协作方案,比如REST、Web服务以及消息传递等,也是不可或缺的。 你知道吗?在我们使用Spring时,容器中存放的所有对象,在Spring启动的时候就完成了实

    2024年02月05日
    浏览(40)
  • spring cloud gateway中出现503 spring cloud gateway中出现503

    当搭建网关模块的时候出现503的错误的最大的可能就是没有设置负载均衡的依赖包  原先搭建的时候采用的是下面的方式进行设置的 上面的这种方式可以直接进行注册和发现,但是要求必须导入下面的依赖 希望简单的随笔能够帮助你!

    2024年02月11日
    浏览(52)
  • 【Spring Cloud 八】Spring Cloud Gateway网关

    【Spring Cloud一】微服务基本知识 【Spring Cloud 三】Eureka服务注册与服务发现 【Spring Cloud 四】Ribbon负载均衡 【Spring Cloud 五】OpenFeign服务调用 【Spring Cloud 六】Hystrix熔断 【Spring Cloud 七】Sleuth+Zipkin 链路追踪 在项目中是使用了Gateway做统一的请求的入口,以及统一的跨域处理以及

    2024年02月12日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包