【SpringBoot系列】Spring cloud Gateway 动态路由到底有多简单

🤵‍♂️ 个人主页:@香菜的个人主页,加 ischongxin ,备注csdn

✍🏻作者简介:csdn 认证博客专家,游戏开发领域优质创作者,华为云享专家,2021年度华为云年度十佳博主

🐋 希望大家多多支持,我们一起进步!😄

如果文章对你有帮助的话,

欢迎评论 💬点赞👍🏻 收藏 📂加关注+

系列文章:Spring Boot学习大纲,可以留言自己想了解的技术点

 

目录

1、概念解析

2、hello word

2.1 加入spring cloud gateway依赖

2.2 配置路由

2.3 测试

3、自定义filter

3.1 filter的分类

3.2 实现局部过滤器

3.3 自定义全局过滤器

4、自定义router

4.1 原理

4.1.1RouteDefinition 和Route的区别

4.1.2 路由的加载

4.2 实现自定义路由

4.3 Gateway的执行流程

5、内置filter 和Predicate

6、一些点

7、总结


1、概念解析

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/ 

Spring Cloud Gateway

1️⃣ 路由(route):路由是网关最基础的部分,路由信息由一个ID,一个目的URL、一组断言工厂和一 组Filter组成。如果断言为真,则说明请求URL和配置的路由匹配。

2️⃣ 断言(Predicate):Java8中的断言函数,Spring Cloud Gateway中的断言函数输入类型是 Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配 来自http Request中的任何信息,比如请求头和参数等。

3️⃣ 过滤器(Filter):一个标准的Spring WebFilter,Spring Cloud Gateway中的Filter分为两种类型: Gateway Filter和Global Filter。过滤器Filter可以对请求和响应进行处理。

2、hello word

2.1 加入spring cloud gateway依赖

创建springboot项目,加入spring cloud gateway 依赖

pom文件如下,注:有用的没几行,就是加入gateway的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xin</groupId>
    <artifactId>gateway-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway-test</name>
    <description>gateway-test</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2022.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2.2 配置路由

不喜欢properties的配置,结构不明显,所以一般使用 application.yml

配置如下

spring:
  cloud:
    gateway:
      routes:
        - id: after_route
          uri: http://192.168.3.8:29001
          predicates:
            - Path=/road/**
          filters:
            - StripPrefix=1

这里加入了一个路由的配置:

路由的服务是 http://192.168.3.8:29001

路由的逻辑是路径中以road开始的路径

过滤器是StripPrefix ,会去除路径中的第一个,也就是road ,最终的实际路径为 uir+ path后面的***

2.3 测试

在浏览器中输入

http://localhost:8080/road/magic/web/index.html 可以看到结果

3、自定义filter

3.1 filter的分类

Gateway分为全局过滤器GlobalFilter和局部过滤器GatewayFilter,局部过滤器只有在路由配置中针对路由ID配置了才会使用,对应配置中的

filters属性。

3.2 实现局部过滤器

局部过滤器相当于对于每个路由会有一个实例,Gateway路由过滤器通过GatewayFilterFactory这个工厂类生成。

注意点:

1、在配置时会去掉FilterFactory 比如 StripPrefixGatewayFilterFactory 配置时使用StripPrefixGatewayFilterFactory

2、config接收配置的参数

@Component
public class TokenCheckGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenCheckGatewayFilterFactory.Config> {

    public TokenCheckGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            String token = exchange.getRequest().getHeaders().getFirst("username");

            // 是否登录成功状态
            if (token != null) {
                // 合法
                // 将用户id作为参数传递下去
                return chain.filter(exchange);
            }

            //不合法(响应未登录的异常)
            ServerHttpResponse response = exchange.getResponse();
            //设置headers
            HttpHeaders httpHeaders = response.getHeaders();
            httpHeaders.add("Content-Type", "application/json; charset=UTF-8");
            httpHeaders.add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
            //设置body
            String warningStr = "未登录或登录超时";
            DataBuffer bodyDataBuffer = response.bufferFactory().wrap(warningStr.getBytes());

            return response.writeWith(Mono.just(bodyDataBuffer));
        };
    }
    static class Config {}
}

3.3 自定义全局过滤器

全局过滤器是所有的请求都会经过,全局只有一个实例,需要实现GlobalFilter和 Ordered 接口

看下一个黑名单的实现。

@Component
@Slf4j
//  TODO 改为动态判断
public class BlackFilter implements GlobalFilter, Ordered {
    private  static final List<String> blackList=new ArrayList<>();
    static {
        blackList.add("0:0:0:0:0:0:0:1");//模拟本机ip地址
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response =exchange.getResponse();
        String clientIp = request.getRemoteAddress().getHostString();
        if (blackList.contains(clientIp)){
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            log.error(clientIp+"在黑名单中,拒绝访问");
            String data = "request be denied";
            DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
            return response.writeWith(Mono.just(wrap));
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

4、自定义router

4.1 原理

4.1.1RouteDefinition 和Route的区别

RouteDefinition 是对配置的读取的对象,纯字符串配置

Route 是将定义实例化之后的对象,比如RouteDefinition 的filter 和 Predicate的实例化对象

4.1.2 路由的加载

先看下类图

RouteLocator 接口用于获取路由信息,其有三个实现类

  • RouteDefinitionRouteLocator
  • CompositeRouteLocator
  • CachingRouteLocator

最终使用的是CachingRouteLocator,它包装了CompositeRouteLocator,而CompositeRouteLocator则组合了所有的RouteDefinitionRouteLocator。

RouteDefinitionRouteLocator 与 RouteDefinitionLocator比较容易混淆,前者是一个RouteLocator(路由定位器),后者是一个RouteDefinitionLocator(路由定义定位器),前者的 RouteDefinitionRouteLocator 主要从后者获取路由定义信息。

4.2 实现自定义路由

从原理中可以看到,我们只要实现自己的RouteDefinitionRouteLocator 就可以了 ,Gateway会自动加载路由

下面是项目中实现的从数据库中加载路由的代码

@Component
public class MysqlRouteLocator implements RouteDefinitionLocator {
    @Resource
    GatewayService gatewayService;
    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> definitionList = new ArrayList<>();
        try {
            definitionList = gatewayService.loadRouteDefinition();
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
        return Flux.fromIterable(definitionList);
    }
}

4.3 Gateway的执行流程

Gateway的执行流程如下:

1:Gateway的客户端回向Spring Cloud Gateway发起请求,请求首先会被HttpWebHandlerAdapter进行提取组装成网关的上下文,然后网关的上下文会传递到DispatcherHandler。

2:DispatcherHandler是所有请求的分发处理器,DispatcherHandler主要负责分发请求对应的处理器,比如将请求分发到对应RoutePredicateHandlerMapping(路由断言处理器映射器)。

3:路由断言处理映射器主要用于路由的查找,以及找到路由后返回对应的FilteringWebHandler。

4:FilteringWebHandler主要负责组装Filter链表并调用Filter执行一系列Filter处理,然后把请求转到后端对应的代理服务处理,处理完毕后,将Response返回到Gateway客户端。
在Filter链中,通过虚线分割Filter的原因是,过滤器可以在转发请求之前处理或者接收到被代理服务的返回结果之后处理。所有的Pre类型的Filter执行完毕之后,才会转发请求到被代理的服务处理。被代理的服务把所有请求完毕之后,才会执行Post类型的过滤器。
 

5、内置filter 和Predicate

6、一些点

1、RefreshRoutesEvent  发布此事件会将各个routerDefinitionLocator加载的路由放入cache中

2、可以使用Nacos或者其他的服务发现

3、在配置中使用lb://service_name 可以启用负载均衡

7、总结

spring cloud gateway 使用了webflux ,在编程的时候还是有一些不适应,但是好在gateway提供了足够多的Predicate和Filter

在日常的使用中足够了,但是定制还是蛮费劲的,不适应reactor编程方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

香菜+

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值