美文网首页
SpringCloud Gateway原理解析(一)

SpringCloud Gateway原理解析(一)

作者: sunyelw | 来源:发表于2021-02-21 10:35 被阅读0次

    [poc]

    1/搭建项目

    1.1/搭建流程

    依赖项

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    

    spring-cloud-gateway 不能用 web, 要用也是用 webflux

    去掉以下依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    

    因为 spring cloud gateway 是基于 webflux 的,如果非要 web 支持的话需要导入 spring-boot-starter-webflux 而不是 spring-boot-start-web

    参见 gateway 报错 ServerCodecConfigurer

    重要 Spring Cloud Gateway 依赖 Spring Boot和 Spring Webflux 提供的 Netty runtime。

    它不能在传统的 Servlet 容器中工作或构建为 WAR

    1.2/路由

    spring:
      application:
        name: nacos-gateway
      cloud:
        nacos:
          server-addr: localhost:8848
        gateway:
          discovery:
            locator:
              enabled: true # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
          routes:
            - id: test-rule
              uri: lb://nacos-client
              order: -1
              predicates:
                - Path=/api2/**
              filters:
                - StripPrefix=1
    
    • id:我们自定义的路由 ID,保持唯一
    • uri:目标服务地址
    • predicates:路由条件,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。
    • filters:过滤规则,

    上面那段路由配置表示所有已包含 /api2/ 的url都会被路由到 client-manage服务,StripPrefix=1表示路由时会去除/api2/。

    测试

    • 服务自身调用
    ☁  scg_project  curl http://localhost:8284/hello
    hello 8284
    ☁  scg_project  curl http://localhost:8285/hello
    hello 8285
    
    • 网关调用
    ☁  scg_project  curl http://localhost:8283/api2/hello
    hello 8284
    ☁  scg_project  curl http://localhost:8283/api2/hello
    hello 8285
    

    上述配置还可以用代码实现

    @Bean
    public RouteLocator divRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(r -> r.path("/api2/**")
                        .filters(f -> f.stripPrefix(1))
                        .uri("lb://nacos-client")
                        .order(0)
                        .id("test-bean-rule"))
                .build();
    }
    

    1.3/动态路由

    org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint#save

    https://www.cnblogs.com/xmzJava/p/10767365.html

    2/概述

    2.1/三要素

    这是路由的三要素 一个成熟的路由最重要的部分就是由这三部分组成
    也是SCG的三要素 不管做什么都是围绕这三个或其中的几个.

    2.2/路由断言Factories

    After / Before / Between / Cookie / Header / Host / Method / Path

    自带的有十个, 可以自行拓展

    自带路由断言

    简单点, 路由断言的意思就是判断这个请求是不是属于这条路由.

    2.3/过滤器

    2.3.1 过滤器示例

    过滤器

    配置的两种方式

    spring:
      cloud:
        gateway:
          routes:
          - id: set_status_route
            uri: https://example.org
            filters:
            - name: SetStatus
              args:
                status: 401
          - id: set_statusshortcut_route
            uri: https://example.org
            filters:
            - SetStatus=401 # shortcut 方式
    
    2.3.2 过滤器实现

    要实现一个拦截器, 需要实现两个( Ordered 非必要 )接口

    GlobalFilter, Ordered

    • Ordered的值越小, 优先级越高, 默认 2147483647 (最小)
    • @Ordered 注解优先

    讲到过滤器就不可不提一下责任链这种经典的设计模式

    责任链模式中 最重要的两个元素

    • 排好序的过滤器链 -> 过滤器链表
    • 当前序号 -> 链中的具体哪个过滤器

    过滤器链 GatewayFilterChain / DefaultGatewayFilterChain

    过滤器 GatewayFilter

    -> LoadBalancerClientFilter ("lb")

    -> NettyRoutingFilter ("http/https")

    参考 StripPrefixGatewayFilterFactory

    直接继承了 AbstractGatewayFilterFactory<StripPrefixGatewayFilterFactory.Config>

    • StripPrefixGatewayFilterFactory.Config 就是拦截器后面带的参数, 这里就是一个int值, 表示要截取几位
    • AbstractGatewayFilterFactory 提供了 apply 方法, 入参就是 config, 返回一个 GatewayFilter 实例

    常见的责任链模式还有 Servlet 的 Filter

    其实所有的拦截器链都有一个特性: 当前拦截器可以决定是否要调用下一个拦截器 (直接)

    2.3.3 过滤器分类

    <1>从 实现/作用 上来分

    其实实现一个过滤器有两种方式:

    • 创建一个继承了 AbstractGatewayFilterFactory 类的 XxxGatewayFilterFactory 类, 然后在XxxGatewayFilterFactory 的 apply 方法中返回一个 GatewayFilter.
    • 直接实现 GlobalFilter 接口 重写 filter 方法.

    区别就是作用域不同(路由级别/全局级别) .

    SCG 最灵活的一点 插件化过滤器

    SCG 自带的局部过滤器有 30 种


    局部过滤器

    SCG 自带的全局过滤器有 10 种

    全局过滤器

    准确地说应该是九种, 第一种只是一个说明.

    2.3.4 Default-GatewayFilter

    不过 SCG 提供了一种将路由级别的过滤器提升到全局的简单方式

    To add a filter and apply it to all routes, you can use spring.cloud.gateway.default-filters. This property takes a list of filters. The following listing defines a set of default filters:

    spring:
      cloud:
        gateway:
          default-filters:
          - AddResponseHeader=X-Response-Default-Red, Default-Blue
          - PrefixPath=/httpbin
    

    这样这两个过滤器就变成全局级别的了.

    还有一点很重要的就是命名

    官方文档明确指出 自定义过滤器的名字需要以 GatewayFilterFactory 结尾

    naming

    2.4/路由定义

    定义一个路由大约有四种方式

    2.4.1 配置方式
    spring.cloud.gateway.route...
    

    最简单直接的一种方式

    4.2 服务发现
    spring.cloud.gateway.locator...
    
    • ReactiveCompositeDiscoveryClient_[serviceId]
    • 从注册中心拉取注册服务列表
    2.4.3 自定义来源

    实现 RouteDefinitionRepository 接口, 重写 getRouteDefinition 方法

    @Override
    public Flux <RouteDefinition> getRouteDefinitions(){
        log.info("get_route_definition...");
      // 自定义来源 - 配置文件/数据库/redis/内存/mq ...
        List <Router> routerList = getConfig();
        List <RouteDefinition> routeDefinitions = routerList.stream().map(this::transfer).collect(Collectors.toList());
        return Flux.fromStream(routeDefinitions.stream());
    }
    
    2.4.4 硬编码
    @Bean
    public RouteLocator divRouteLocator(RouteLocatorBuilder builder) {
      return builder.routes()
        .route(r -> r.path("/api3/**")
               .filters(f -> f.stripPrefix(1))
               .uri("lb://nacos-client")
               .order(-100)
               .id("test-bean-rule"))
        .build();
    }
    

    前三种分别对应了 RouteDefinitionLocator 的三种实现, 最后一种是直接生成了一个 RouteLocator 类 ( DSL 风格 )

    CompositeRouteLocator 里的 delegates 就有以下两种

    org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder$Builder$$Lambda$494/1864630663@29f8134
    org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator@77a9ac36
    
    • lambda 这种就是硬编码方式生成的
    • 其他三种都会以 RouteDefinitionRouteLocator 的方式生效

    还有这么多....

    image.png

    先写到这吧, 下次再补.

    醒了个大早却赶了晚集, 还没饭吃...
    写了点东西有点感觉了赶紧去看 Nacos ~

    相关文章

      网友评论

          本文标题:SpringCloud Gateway原理解析(一)

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