三分钟了解Spring Cloud Gateway路由转发之自动路由

这篇具有很好参考价值的文章主要介绍了三分钟了解Spring Cloud Gateway路由转发之自动路由。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

大家好,我是冰点,今天和大家分享一下关于Spring Cloud Gateway 利用服务注册与发现实现自动路由的原理和源码解读。希望对大家有所帮助。
三分钟了解Spring Cloud Gateway路由转发之自动路由

一、前言

今天有个新同学,问我为什么我们的网关服务Spring Cloud Gateway,没有配置路由就可以将请求到路由服务,说他们之前的项目的网关是将路由配置在配置文件中。指定路由类似以下写法。而在现在的项目的配置文件中未发现任何路由配置。觉得很奇怪,Spring-Cloud-Gateway 是如何将请求路由到指定的服务的呢。我让他比对一下配置文件有什么不同,他说就是只有一个spring.cloud.gateway.discovery.locator.enabled=true

如下配置一般是大多数项目配置路由的我们一般称之为静态路由,是由配置文件硬编码后在程序启动的时候加载的。

spring:
  cloud:
    gateway:
      discovery:
        locator:
          lower-case-service-id: true # 忽略服务名的大小写
      routes:
        - id: service1
          uri: lb://service1
          predicates:
            - Path=/service1/**
        - id: service2
          uri: lb://service2
          predicates:
            - Path=/service2/**

除了上述的路由配置外,其实我们通俗的将gateway 的路由可以分为三种

  1. 静态路由
  2. 动态路由
  3. 自动路由

下面我们详细了解一下这三种路由
Spring Cloud Gateway 支持三种类型的路由:静态路由、动态路由和自动路由。

二、路由配置

1. 静态路由

静态路由是指在配置文件中预先定义好的路由规则,它们在应用启动时就已经存在。静态路由的优点是可以快速定位和处理请求,缺点是需要手动配置,不支持动态添加、修改和删除路由规则。

在 Spring Cloud Gateway 中,可以通过配置文件来定义静态路由规则。例如:

spring:
  cloud:
    gateway:
      routes:
        - id: service1
          uri: http://localhost:8081
          predicates:
            - Path=/service1/**
        - id: service2
          uri: http://localhost:8082
          predicates:
            - Path=/service2/**

这段配置文件定义了两个静态路由规则,分别对应于服务 service1 和服务 service2。当请求的路径匹配 /service1/** 时,它就会被转发到 http://localhost:8081;当请求的路径匹配 /service2/** 时,它就会被转发到 http://localhost:8082。

2. 动态路由

动态路由是指在运行时动态添加、修改和删除路由规则,可以根据不同的条件动态地调整路由规则,例如根据请求路径、请求头、请求参数等条件。动态路由的优点是可以根据实际情况调整路由规则,缺点是需要额外的管理和维护成本。
在 Spring Cloud Gateway 中,可以通过 API 来动态添加、修改和删除路由规则。例如:

@Autowired
private RouteDefinitionWriter routeDefinitionWriter;

public void addRoute(String id, String uri, String predicates) {
    RouteDefinition routeDefinition = new RouteDefinition();
    routeDefinition.setId(id);
    routeDefinition.setUri(URI.create(uri));
    routeDefinition.setPredicates(Collections.singletonList(new PredicateDefinition(predicates)));
    routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
}

public void updateRoute(String id, String uri, String predicates) {
    RouteDefinition routeDefinition = new RouteDefinition();
    routeDefinition.setId(id);
    routeDefinition.setUri(URI.create(uri));
    routeDefinition.setPredicates(Collections.singletonList(new PredicateDefinition(predicates)));
    routeDefinitionWriter.delete(Mono.just(routeDefinition.getId())).then(Mono.defer(() -> {
        routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
        return Mono.empty();
    })).subscribe();

}

public void deleteRoute(String id) {
    routeDefinitionWriter.delete(Mono.just(id)).subscribe();
}

通过注入 RouteDefinitionWriter 对象来操作路由规则。 addRoute 方法可以添加一条路由规则, updateRoute 方法可以修改一条路由规则, deleteRoute 方法可以删除一条路由规则。这些操作会实时生效,不需要重启应用。需要在 Spring Boot 应用启动时加载 RouteDefinitionLocator 对象,以便正确加载动态路由规则。

3. 自动路由

自动路由是指根据服务注册中心的服务信息自动生成路由规则。当有新的服务上线或下线时,路由规则也会自动更新。自动路由的优点是可以根据实际情况自动调整路由规则,缺点是需要服务注册中心的支持。其实服务发现可以支持很多种,主要实现spring cloud 提供的接口即可。下次我专门写一篇介绍

服务发现功能的实现可以通过 Spring Cloud Commons 中的 DiscoveryClient 类实现。Spring Cloud
Discovery 可以与多种服务发现组件集成,包括 EurekaConsulZookeeper 等。Spring Cloud
Gateway 会自动与 Spring Cloud Discovery 集成,可以使用 Spring Cloud Discovery
来获取服务实例列表,并将这些服务实例转换为路由规则。大家感兴趣可以先了解一下这两个接口。
三分钟了解Spring Cloud Gateway路由转发之自动路由

在 Spring Cloud Gateway 中,可以通过配置服务注册中心来启用自动路由功能。例如:

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true

启用了服务发现功能,并将服务 ID 转换为小写

三、Spring Cloud Gateway 是如何实现动态路由

客户端发送请求到Spring Cloud Gateway,Gateway Handler Mapping确定请求与路由匹配,则会将请求交给Gateway Web Handler处理。

工作原理

图片来源spring官网 https://cloud.spring.io/spring-cloud-gateway/reference/html/
三分钟了解Spring Cloud Gateway路由转发之自动路由

源码解析

Spring Cloud Gateway 是一款基于 Spring Framework 和 Spring Boot 的网关框架,它提供了统一的路由转发、负载均衡、请求过滤和请求转换等功能。在 Spring Cloud Gateway 中,路由转发是其中最核心的功能之一。

下面是 Spring Cloud Gateway 路由转发的原理和源码解析。

路由转发原理
  1. Spring Cloud Gateway 的路由转发基于 Netty 和 Reactor 实现。当一个请求到达 Spring Cloud
    Gateway 时,它会首先经过一系列过滤器的处理,然后根据路由规则将请求转发到正确的目标地址。

  2. 路由规则由路由配置组件管理,它可以通过多种方式来创建,例如基于配置文件的路由配置、基于 Java代码的路由配置、基于服务发现的路由配置等。每个路由规则包含一个路由条件和一个目标 URI,当一个请求满足路由条件时,它就会被转发到目标
    URI。

  3. 路由条件由路由规则的路由条件工厂类创建,例如
    PathRoutePredicateFactory、HeaderRoutePredicateFactory、MethodRoutePredicateFactory等。它们可以根据请求的路径、请求头、请求方法等条件来判断一个请求是否满足路由条件。

  4. 目标 URI 可以通过多种方式指定,例如硬编码的 URI、基于服务发现的 URI、基于请求头的 URI 等。在确定了目标 URI 后,Spring Cloud Gateway 会将请求转发到目标 URI,并将响应返回给客户端。

路由转发源码解析

在 Spring Cloud Gateway 中,路由转发的核心代码位于 org.springframework.cloud.gateway.handler 包中。其中,RoutePredicateHandlerMapping 类是 Spring Cloud Gateway 的路由转发入口,它继承了 AbstractHandlerMapping 类,并实现了其中的 getHandlerInternal 方法。

RoutePredicateHandlerMapping 的源码解析 为了方便理解,添加了中文注释

public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {

    private final Map<String, RoutePredicateFactory> predicates; // 路由条件工厂类映射表
    private final GatewayFilterHandlerFilter filterHandlerFilter; // 过滤器处理器
    private final Map<String, Object> globalFilters; // 全局过滤器映射表
    private final RouteDefinitionLocator routeDefinitionLocator; // 路由规则定位器

    public RoutePredicateHandlerMapping(List<RoutePredicateFactory> predicates,
                                        GatewayFilterHandlerFilter filterHandlerFilter,
                                        List<GlobalFilter> globalFilters,
                                        RouteDefinitionLocator routeDefinitionLocator) {
        this.predicates = predicates.stream()
                .collect(Collectors.toMap(RoutePredicateFactory::name, Function.identity())); // 将路由条件工厂类列表转换为路由条件工厂类映射表
        this.filterHandlerFilter = filterHandlerFilter;
        this.globalFilters = globalFilters.stream()
                .collect(Collectors.toMap(GlobalFilter::name, Function.identity())); // 将全局过滤器列表转换为全局过滤器映射表
        this.routeDefinitionLocator = routeDefinitionLocator;
        setOrder(-1); // 设置路由转发的优先级
    }

    @Override
    protected Object getHandlerInternal(ServerHttpRequest request) throws Exception {
        List<RouteDefinition> definitions = this.routeDefinitionLocator.getRouteDefinitions().collectList().block(); // 获取所有路由规则
        if (definitions == null) { // 如果路由规则列表为空,则返回 null
            return null;
        }
        for (RouteDefinition routeDefinition : definitions) { // 遍历所有路由规则
            RoutePredicateFactory predicate = this.predicates.get(routeDefinition.getPredicate().getName());            RoutePredicate routePredicate = predicate.apply(routeDefinition.getPredicate().getArgs()); // 创建路由条件
            if (routePredicate.test(request)) { // 判断请求是否满足路由条件
                Route route = new Route(routeDefinition.getId(), routeDefinition.getUri(), routeDefinition.getFilters()); // 创建路由对象
                List<GatewayFilter> gatewayFilters = new ArrayList<>(routeDefinition.getFilters()); // 获取路由规则中的过滤器
                gatewayFilters.addAll(getGlobalFilters()); // 添加全局过滤器
                FilteringWebHandler filteringWebHandler = new FilteringWebHandler(new DefaultWebHandler(), new GatewayFilterChain(gatewayFilters)); // 创建过滤器链
                return new DefaultWebHandlerAdapter().handle(request, filteringWebHandler); // 返回路由转发处理器
            }
        }
        return null;
    }

    private Collection<Object> getGlobalFilters() {
        return this.globalFilters.values(); // 返回全局过滤器集合
    }
}

在 RoutePredicateHandlerMapping 中,首先通过构造方法初始化了路由条件工厂类映射表、过滤器处理器、全局过滤器映射表和路由规则定位器。然后,实现了 AbstractHandlerMapping 中的 getHandlerInternal 方法。在 getHandlerInternal 方法中,首先获取所有路由规则,并遍历每个路由规则。对于每个路由规则,将其路由条件工厂类名称作为 key,从路由条件工厂类映射表中获取对应的路由条件工厂类,并使用路由条件工厂类创建路由条件。然后,判断当前请求是否满足路由条件,如果满足,则创建路由对象,并获取路由规则中的过滤器和全局过滤器。将这些过滤器组成过滤器链,并将过滤器链和默认的 Web 处理器一起作为参数创建过滤器 Web 处理器。最后,使用过滤器 Web 处理器和当前请求创建 DefaultWebHandlerAdapter 的实例,并返回路由转发处理器。

写到这儿其实我们只是了解了一个请求在路由到后台服务之前必须要要经过的几道工序,就如同我最开始从Spring 官网获得的工作原理图。

四 、问题核心

我们来回答最开始的那个问题。那么如果在不配置路由规则的Spring Cloud Gateway 服务中,网关是如何做的转发呢,这才是我们核心问题。

那就不得不说一个重要的核心的接口和实现类 位于spring-cloud-gateway-core-2.x.RELEASE 下。
RouteDefinitionLocator。其实里面就一个核心方法 getRouteDefinitions

三分钟了解Spring Cloud Gateway路由转发之自动路由

DiscoveryClientRouteDefinitionLocator源码解析

DiscoveryClientRouteDefinitionLocator 是RouteDefinitionLocator 实现类。是 Spring Cloud Gateway 提供的一个基于服务发现的路由规则定位器,它可以自动将服务实例列表转换为路由规则,从而实现基于服务发现的路由配置。

为了方便大家理解,我在源码上添加了一些注释

public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
    // 服务发现客户端
    private final DiscoveryClient discoveryClient;
    // 路由规则转换器
    private final RouteDefinitionLocator routeDefinitionLocator;
    // 服务过滤器
    private final Predicate<ServiceInstance> predicate;
	// 默认使用所有服务实例
    public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, RouteDefinitionLocator routeDefinitionLocator) {
        this(discoveryClient, routeDefinitionLocator, instance -> true); // 默认使用所有服务实例
    }
	// 第二个构造方法可以指定服务过滤器
    public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, RouteDefinitionLocator routeDefinitionLocator, Predicate<ServiceInstance> predicate) {
        this.discoveryClient = discoveryClient;
        this.routeDefinitionLocator = routeDefinitionLocator;
        this.predicate = predicate;
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(getServiceNames()) // 获取所有服务名称
                .flatMap(this::getRoutes) // 遍历每个服务名称,获取该服务的路由规则
                .flatMap(routeDefinitionLocator::getRouteDefinitions) // 转换路由规则
                .doOnNext(route -> logger.debug("RouteDefinition matched: " + route)); // 打印日志
    }

    private List<String> getServiceNames() {
        return discoveryClient.getServices(); // 获取服务名称列表
    }

    private Mono<RouteDefinition> getRoutes(String serviceName) {
        return Mono.just(new RouteDefinition()) // 创建一个新的 RouteDefinition 对象
                .flatMap(routeDefinition -> Flux.fromIterable(getInstances(serviceName))) // 获取该服务的所有实例
                .filter(predicate) // 过滤服务实例
                .map(this::getInstanceRoute) // 将服务实例转换为路由规则
                .doOnNext(route -> logger.debug("RouteDefinition created: " + route)) // 打印日志
                .reduce(new RouteDefinition(), this::mergeRouteDefinitions); // 合并所有路由规则
    }

    private List<ServiceInstance> getInstances(String serviceName) {
        return discoveryClient.getInstances(serviceName); // 获取指定服务的所有实例
    }

    private RouteDefinition getInstanceRoute(ServiceInstance instance) {
        RouteDefinition route = new RouteDefinition(); // 创建一个新的 RouteDefinition 对象
        route.setId(instance.getServiceId()); // 设置路由规则的 ID 为服务名称
        URI uri = instance.getUri(); // 获取服务实例的 URI
        if (uri != null) {
            route.setUri(uri); // 设置路由规则的 URI
        }
        return route;
    }

    private RouteDefinition mergeRouteDefinitions(RouteDefinition route1, RouteDefinition route2) {
        route1.getFilters().addAll(route2.getFilters()); // 合并过滤器
        route1.getPredicates().addAll(route2.getPredicates()); // 合并谓词
        return route1;
    }
}
  1. DiscoveryClientRouteDefinitionLocator 类的主要作用是从服务注册中心获取服务信息并将其转换为路由规则。它实现了 RouteDefinitionLocator 接口,用于获取路由规则列表。具体来说,它通过 DiscoveryClient 类获取所有服务名称,遍历每个服务名称,再通过 DiscoveryClient 类获取该服务的所有实例,最后将实例信息转换为路由规则。
  2. getRouteDefinitions 方法是 DiscoveryClientRouteDefinitionLocator类的核心方法,用于获取所有的路由规则。它通过 Flux.fromIterable() 获取所有服务名称,然后通过 flatMap()方法遍历每个服务名称,获取该服务的路由规则。获取路由规则的方法是 getRoutes(),该方法通过 Mono.just()创建一个新的 RouteDefinition 对象,然后通过 Flux.fromIterable() 获取该服务的所有实例,再通过filter() 方法过滤服务实例,接着调用getInstanceRoute方法将服务实例转换为路由规则,最后通过reduce() 方法将所有路由规则合并成一个RouteDefinition 对象。在合并路由规则时,会调 mergeRouteDefinitions 方法实现合并过滤器和谓词的操作。
  3. getServiceNames获取所有服务名称,它通过 DiscoveryClient 类的 getServices() 方法实现。
  4. getInstances() 获取指定服务的所有实例,它通过 DiscoveryClient 类的 getInstances() 方法实现。
  5. getInstanceRoute() 方法用于将服务实例转换为路由规则,它创建一个新的 RouteDefinition对象,将服务名称作为路由规则的 ID,将服务实例的 URI 作为路由规则的 URI,并返回该路由规则对象。
  6. mergeRouteDefinitions方法用于合并路由规则,它将两个路由规则对象的过滤器和谓词合并到一个路由规则对象中,并返回该路由规则对象。

五、总结

所以总而言之要回答上面的问题,还是必须要有服务注册与发现的基础知识,才能理解。而实现这个特性的关键类=DiscoveryClientRouteDefinitionLocator 类,它通过服务发现客户端从服务注册中心获取服务信息并将其转换为路由规则,并实现了 RouteDefinitionLocator接口,用于获取路由规则列表。

好了今天的分享就到这儿,希望三分钟的阅读对你有所收获。我是冰点,下次再见。文章来源地址https://www.toymoban.com/news/detail-475814.html

到了这里,关于三分钟了解Spring Cloud Gateway路由转发之自动路由的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Spring Cloud Gateway 监控、多网关实例路由共享 | Spring Cloud 18

    Actuator 是 Spring Boot 提供的用来对应用系统进行监控的功能模块,借助于 Actuator 开发者可以很方便地对应用系统某些监控指标进行查看、统计等。 Actuator 的核心是端点 Endpoint 。 Endpoint 可以让我们监视应用程序并与其交互。 Spring Boot 包含许多内置端点,并允许您添加自己的端

    2024年02月09日
    浏览(60)
  • spring cloud gateway网关(一)之网关路由

    1、gateway相关介绍 在微服务架构中,系统往往由多个微服务组成,而这些服务可能部署在不同机房、不同地区、不同域名下。这种情况下,客户端(例如浏览器、手机、软件工具等)想要直接请求这些服务,就需要知道它们具体的地址信息,例如 IP 地址、端口号等。这种客户

    2024年02月08日
    浏览(41)
  • 【Spring Cloud Alibaba】8.路由网关(Gateway)

    接下来对服务消费者添加路由网关来实现统一访问接口,本操作先要完成之前的步骤,详情请参照【Spring Cloud Alibaba】Spring Cloud Alibaba 搭建教程 Spring Cloud Gateway 是 Spring 官方基于 Spring 5.0 , Spring Boot 2.0 和 Project Reactor 等技术开发的网关,该项目提供了一个库,用于在 Spring W

    2023年04月24日
    浏览(40)
  • 【源码】Spring Cloud Gateway 是在哪里匹配路由的?

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

    2023年04月24日
    浏览(38)
  • 【深入解析spring cloud gateway】02 网关路由断言

    断言是路由配置的一部分,当断言条件满足,即执行Filter的逻辑,如下例所示 当请求路径满足条件/red/,即添加头信息:X-Request-Red,value为Blue-{segment},segment是路径里面带的信息。 gateWay的主要功能之一是转发请求,转发规则的定义主要包含三个部分 Route(路由) 路由是网关

    2024年02月09日
    浏览(42)
  • 第八章 : Spring cloud 网关中心 Gateway (动态路由)

    第八章 : Spring cloud 网关中心 Gateway (动态路由) 前言 本章知识点:重点介绍动态网关路由的背景、动态路由与静态路由的概念,以及如何基于Nacos实现动态网关路由 的实战案例。 背景 前面章节介绍了Spring Cloud Gateway提供的配置路由规则的两种方法,但都是在Spring Cloud Ga

    2024年01月19日
    浏览(48)
  • 第七章 : Spring cloud 网关中心 Gateway (静态路由)

    第七章 : Spring cloud 网关中心 Gateway (静态路由) 前言 本章知识点:本章将会介绍什么是Spring Cloud Gateway、为什么会出现Spring Cloud Gateway,以及Spring Cloud Gateway的工作原理和实战用法,以及Spring Cloud Gateway 路由概念以及基于nacos注册中心Spring Cloud Gateway 静态路由的实战。 什么

    2024年02月02日
    浏览(58)
  • Spring-cloud-gateway 路由配置方式及匹配规则

    1.1 基础路由配置⽅式 如果请求的⽬标地址,是单个的URI资源路径,配置⽂件实例如下: 各字段含义如下。 id:我们⾃定义的路由 ID,保持唯⼀ uri:⽬标服务地址 predicates:路由条件,Predicate 接受⼀个输⼊参数,返回⼀个布尔值结果。该接⼝包含多种默 认⽅法来将 Predicate

    2024年02月04日
    浏览(45)
  • Spring-Cloud-Gateway如何自定义路由过滤器?

    遇到这么一个面试题:自定义网关过滤器实现把url中的请求参数放到http的header中传递给微服务。 我们知道网关的一个重要的作用就是路由转发,路由表的配置大概是这个样子: 其中的filters就是配置的路由过滤器,Spring已经内置了31个路由的过滤器,这些过滤器都是 org.spring

    2024年02月16日
    浏览(40)
  • Spring Cloud 2022.x版本使用gateway和nacos实现动态路由和负载均衡

    Spring Cloud Alibaba官方:https://sca.aliyun.com/zh-cn/ Spring Cloud官网:https://spring.io/projects/spring-cloud Spring Cloud与Spring Cloud Alibaba版本对应说明:https://sca.aliyun.com/zh-cn/docs/2022.0.0.0/overview/version-explain 下载地址:https://github.com/alibaba/nacos/releases 下载编译压缩并解压:nacos-server-2.2.3.zip。 1.1、

    2024年02月11日
    浏览(41)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包