SpringCloud Gateway原理解析(一)

[poc]

1/搭建项目

1.1/搭建流程

依赖项


  org.springframework.cloud
  spring-cloud-starter-gateway

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

去掉以下依赖


    org.springframework.boot
    spring-boot-starter-web

因为 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/三要素

  • Route 路由:gateway 的基本构建模块。它由ID、目标URI、断言集合和过滤器集合组成。如果聚合断言结果为真,则匹配到该路由。

  • Predicate 断言:这是一个Java 8 Function Predicate。输入类型是 Spring Framework ServerWebExchange。这允许开发人员可以匹配来自 HTTP 请求的任何内容,例如Header或参数。

  • Filter 过滤器:这些是使用特定工厂构建的 Spring FrameworkGatewayFilter 实例。所以可以在返回请求之前或之后修改请求和响应的内容。

这是路由的三要素 一个成熟的路由最重要的部分就是由这三部分组成
也是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 就是拦截器后面带的参数, 这里就是一个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  getRouteDefinitions(){
    log.info("get_route_definition...");
  // 自定义来源 - 配置文件/数据库/redis/内存/mq ...
    List  routerList = getConfig();
    List  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原理解析(一))