【Spring Cloud】Gateway组件的三种使用方式

news2024/11/18 9:32:59

🎉🎉欢迎来到我的CSDN主页!🎉🎉

🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚

🌟推荐给大家我的专栏《Spring Cloud》。🎯🎯

👉点击这里,就可以查看我的主页啦!👇👇

Java方文山的个人主页

🎁如果感觉还不错的话请给我点赞吧!🎁🎁

💖期待你的加入,一起学习,一起进步!💖💖

请添加图片描述

目录

🌟前言

✨创建模块

✨使用Gateway的三种方式

🍃方法一

🍃方法二

🍃方法三

 

🌟前言

        Spring Cloud Gateway是 Spring 官方基于 Spring5.0 SpringBoot2.0 Project Reactor 等技术开发的网关旨在为微服务框架提供一种简单而有效的统一的API 路由管理方式,统一访问接口。
        Spring Cloud Gateway作为 Spring Cloud 生态体系中的网关,目标是替代 Netflix Zuul ,其不仅提供统 一的路由方式,并且基于Filter 链的方式提供了网关基本的功能,例如:安全、监控 / 埋点和限流等等,而且它是基于Netty 的响应式开发模式。

✨创建模块

我们的Gatewa既然是负责网络路由的,那么它首先肯定是个模块,所以我们的第一步就是需要创建一个模块。
修改该模块的pom.xml文件,让其继承父模块及导入相应的依赖
  <parent>
        <groupId>org.example</groupId>
        <artifactId>Cloud</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.35</version>
    </dependency>
</dependencies>

因为所有的服务都要接入网关,而服务都在注册中心有记录,所以我们网关要与Nacos关联,首先需要在配置文件中与Nacos做配置并且在启动类开启Nacos

@EnableDiscoveryClient(启动类打上该注解)

server:
  port: 8083
spring:
  cloud:
    nacos:
      server-addr: localhost:8848
  application:
    name: geteway

将全部服务启动就可以看到我们的gateway也被注册到Nacos中啦

✨使用Gateway的三种方式

🍃方法一

gateway:
  discovery:
    locator:
#是否与服务发现组件进行结合,通过service-id(必须设置成大写)转发到具体的服务实例。默认 false
#为true代表开启基于服务发现的路由规则。
        enabled: true
#配置之后访问时service-id无需大写
        lower-case-service-id: true

 

注意:我们的gateway是与spring下的nacos的标签同级别可不要将它写在nacos下面

 

 前面是通过服务直接访问的,后面则是通过网关向服务发起的请求,此时我们的请求已经被官网处理了。

🍃方法二

第二种方式是为了防止使用第一种方式的时候服务名字太长而导致的麻烦,这种方式类似于为服务名又起了一个别名。

    gateway:
      routes:
      # 路由标识(id:标识,具有唯一性)
      - id: user-consumer-api
      #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
        uri: lb://consume
      #优先级,越小越优先
        predicates:
        # 路径匹配,
           - Path=/aa/**
        filters:
      #前缀过滤,请求地址:http://localhost:8084/usr/hello
      #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
            - StripPrefix=1

 这里如果使用的是http://localhost:8083/aa/test01就会映射到consume这个服务,并且通过前缀过滤会过滤掉aa拿到test01就会映射到consume/test01上,得到如下结果👇👇

 

🍃方法三

第三种方式是结合配置读取类进行的,我们将对服务的网关配置写在Nacos,然后再用这个读取类去进行读取,获取我们想要的路由信息。

    gateway:
      nacos:
      server-addr: ${spring.cloud.nacos.server-addr}
      data-id: dynamic-routing.json
      group: DEFAULT_GROUP

首先需要新建一个POJO包将以下类进行创建

package org.example.geteway.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author hgh
 */
@SuppressWarnings("all")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class FilterEntity {

    //过滤器对应的Name
    private String name;

    //路由规则
    private Map<String, String> args = new LinkedHashMap<>();

}
package org.example.geteway.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@SuppressWarnings("all")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ConfigurationProperties(prefix = "gateway.nacos")
@Component
public class GatewayNacosProperties {

    private String serverAddr;
    private String dataId;
    private String namespace;
    private String group;

}
package org.example.geteway.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author hgh
 */
@SuppressWarnings("all")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class PredicateEntity {

    //断言对应的Name
    private String name;

    //断言规则
    private Map<String, String> args = new LinkedHashMap<>();

}
package org.example.geteway.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.ArrayList;
import java.util.List;

/**
 * @author hgh
 */
@SuppressWarnings("all")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class RouteEntity {

    //路由id
    private String id;

    //路由断言集合
    private List<PredicateEntity> predicates = new ArrayList<>();

    //路由过滤器集合
    private List<FilterEntity> filters = new ArrayList<>();

    //路由转发的目标uri
    private String uri;

    //路由执行的顺序
    private int order = 0;

}

最后创建一个配置信息读取类,这个类是一个基于 Spring Cloud Gateway 和 Nacos 的动态路由配置类,它实现了一个 Spring 提供的事件推送接口 ApplicationEventPublisherAware。它的功能主要包括监听 Nacos 的配置变化、解析从 Nacos 读取的路由配置信息(json格式)、路由更新、以及组装和定义路由信息等。通过这个类,可以实现路由信息的动态管理和更新。

package org.example.geteway;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.example.geteway.pojo.FilterEntity;
import org.example.geteway.pojo.GatewayNacosProperties;
import org.example.geteway.pojo.PredicateEntity;
import org.example.geteway.pojo.RouteEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * 此类实现了Spring Cloud Gateway + nacos 的动态路由,
 * 它实现一个Spring提供的事件推送接口ApplicationEventPublisherAware
 */
@SuppressWarnings("all")
@Slf4j
@Component
public class DynamicRoutingConfig implements ApplicationEventPublisherAware {

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    @Autowired
    private GatewayNacosProperties gatewayProperties;

    @Autowired
    private ObjectMapper mapper;

    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    /**
     * 这个方法主要负责监听Nacos的配置变化,这里先使用参数构建一个ConfigService,
     * 再使用ConfigService开启一个监听,
     * 并且在监听的方法中刷新路由信息。
     */
    @Bean
    public void refreshRouting() throws NacosException {
        //创建Properties配置类
        Properties properties = new Properties();
        System.out.println(gatewayProperties);
        //设置nacos的服务器地址,从配置类GatewayProperties中获取
        properties.put(PropertyKeyConst.SERVER_ADDR, gatewayProperties.getServerAddr());
        //设置nacos的命名空间,表示从具体的命名空间中获取配置信息,不填代表默认从public获得
        if (gatewayProperties.getNamespace() != null) {
            properties.put(PropertyKeyConst.NAMESPACE, gatewayProperties.getNamespace());
        }
        //根据Properties配置创建ConfigService类
        ConfigService configService = NacosFactory.createConfigService(properties);
        //获得nacos中已有的路由配置
        String json = configService.getConfig(gatewayProperties.getDataId(), gatewayProperties.getGroup(), 5000);
        this.parseJson(json);

        //添加监听器,监听nacos中的数据修改事件
        configService.addListener(gatewayProperties.getDataId(), gatewayProperties.getGroup(), new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }

            /**
             * 用于接收远端nacos中数据修改后的回调方法
             */
            @Override
            public void receiveConfigInfo(String configInfo) {
                log.warn(configInfo);
                //获取nacos中修改的数据并进行转换
                parseJson(configInfo);
            }
        });

    }

    /**
     * 解析从nacos读取的路由配置信息(json格式)
     */
    public void parseJson(String json) {
        log.warn("从Nacos返回的路由配置(JSON格式):" + json);
        boolean refreshGatewayRoute = JSONObject.parseObject(json).getBoolean("refreshGatewayRoute");
        if (refreshGatewayRoute) {
            List<RouteEntity> list = JSON.parseArray(JSONObject.parseObject(json).getString("routeList")).toJavaList(RouteEntity.class);
            for (RouteEntity route : list) {
                update(assembleRouteDefinition(route));
            }
        } else {
            log.warn("路由未发生变更");
        }
    }


    /**
     * 路由更新
     */
    public void update(RouteDefinition routeDefinition) {

        try {
            this.routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));
            log.warn("路由删除成功:" + routeDefinition.getId());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        try {
            routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
            this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
            log.warn("路由更新成功:" + routeDefinition.getId());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

    }

    /**
     * 路由定义
     */
    public RouteDefinition assembleRouteDefinition(RouteEntity routeEntity) {

        RouteDefinition definition = new RouteDefinition();

        // ID
        definition.setId(routeEntity.getId());

        // Predicates
        List<PredicateDefinition> pdList = new ArrayList<>();
        for (PredicateEntity predicateEntity : routeEntity.getPredicates()) {
            PredicateDefinition predicateDefinition = new PredicateDefinition();
            predicateDefinition.setArgs(predicateEntity.getArgs());
            predicateDefinition.setName(predicateEntity.getName());
            pdList.add(predicateDefinition);
        }
        definition.setPredicates(pdList);

        // Filters
        List<FilterDefinition> fdList = new ArrayList<>();
        for (FilterEntity filterEntity : routeEntity.getFilters()) {
            FilterDefinition filterDefinition = new FilterDefinition();
            filterDefinition.setArgs(filterEntity.getArgs());
            filterDefinition.setName(filterEntity.getName());
            fdList.add(filterDefinition);
        }
        definition.setFilters(fdList);

        // URI
        URI uri = UriComponentsBuilder.fromUriString(routeEntity.getUri()).build().toUri();
        definition.setUri(uri);

        return definition;
    }

}

现在需要我们去Nacos创建对应的配置 dynamic-routing.json

{
  "refreshGatewayRoute": true,
  "routeList": [
    {
      "id": "consumer-api",
      "predicates": [
        {
          "name": "Path",
          "args": {
            "_genkey_0": "/cum/**"
          }
        }
      ],
      "filters": [
        {
          "name": "StripPrefix",
          "args": {
            "_genkey_0": "1"
          }
        }
      ],
      "uri": "lb://consumer",
      "order": 0
    },
    {
      "id": "provider-api",
      "predicates": [
        {
          "name": "Path",
          "args": {
            "_genkey_0": "/pvr/**"
          }
        }
      ],
      "filters": [
        {
          "name": "StripPrefix",
          "args": {
            "_genkey_0": "1"
          }
        }
      ],
      "uri": "lb://provider",
      "order": 0
    }
  ]
}

现在我们就可以通过获取Nacos所配置的路由进行访问了

如果你更改了Nacos的信息也会实时发送改变不用重启服务器

 

请添加图片描述

到这里我的分享就结束了,欢迎到评论区探讨交流!!

💖如果觉得有用的话还请点个赞吧 💖

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1371679.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【2024系统架构设计】 系统架构设计师第二版-面向服务架构设计理论与实践

目录 一 概述 二 SOA的参考架构 三 SOA主要协议和规范 四 SOA设计标准和原则 五 SOA的设计模式 六 SOA的构建和实施 ​

【前端】前后端的网络通信基础操作(原生ajax, axios, fetch)

概述 前后端网络请求工具 原生ajaxfetch apiaxios GET和POST请求 get只能发纯文本 post可以发不同类型的数据&#xff0c;要设置请求头&#xff0c;需要告诉服务器一些额外信息 测试服务器地址 有一些公共的测试 API 可供学习和测试用途。这些 API 允许你发送 HTTP 请求…

浏览器不支持 css 中 :not 表达式的解决方法

问题 使用 :not 表达式的样式在不同浏览器中存在不生效的问题。 原因 不生效是因为浏览器版本较低所导致的。&#xff08;更多详细信息请看&#xff1a;MDN&#xff09; 解决方法 初始写法&#xff1a; .input-group:not(.user-name, .user-passwork){width: auto; }改成…

基于jsp的在线求职招聘信息系统 设计与实现

当前企业求职招聘的方式更多是通过传统的线下招聘会或职业介绍所来实现的&#xff0c;其不但受众具有很大的局限性&#xff0c;而且往往不可能在短时间内招聘的需要的人才。而互联网的普及为企业求职招聘的方式带来了翻天覆地的改变。通过互联网将招聘信息进行发布可以在短时间…

(1)(1.13) SiK无线电高级配置(五)

文章目录 前言 10 可用频率范围 11 DUTY_CYCLE 设置 12 低延迟模式 13 先听后说 (LBT) 14 升级无线电固件 15 MAVLink协议说明 前言 本文提供 SiK 遥测无线电(SiK Telemetry Radio)的高级配置信息。它面向"高级用户"和希望更好地了解无线电如何运行的用户。 1…

Web缓存代理

目录 一.Web缓存代理 配置Nginx 缓存代理&#xff1a; 修改web服务器的配置文件&#xff1a; 修改192.168.233.10代理服务器的配置文件&#xff1a; 访问页面看看&#xff1a; 对于一些实时性要求非常高的页面或数据来说&#xff0c;就不应该去设置缓存&#xff0c;下面来…

STL-vector

目录 1.vector的介绍及使用 1.1 vector的介绍 1.2 vector的使用 1.2.1 vector的定义 1.2.2 vector iterator 的使用 1.2.3 vector 空间增长问题 1.2.3 vector 增删查改 1.2.4 vector 迭代器失效问题。&#xff08;重点&#xff09; 1. 会引起其底层空间改变的操作&#x…

C++:多态究竟是什么?为何能成为面向对象的重要手段之一?

C&#xff1a;多态究竟是什么&#xff1f;为何能成为面向对象的重要手段之一&#xff1f; 前言一、多态的概念二、多态的定义及实现2.1 多态的构成条件2. 2 虚函数2.3 虚函数的重写2.3.1 虚函数重写的例外1&#xff1a;协变(基类与派生类虚函数返回值类型不同)2.3.2 虚函数重写…

【信息论与编码】【北京航空航天大学】实验一、哈夫曼编码【C语言实现】(上)

信息论与编码 实验1 哈夫曼编码 实验报告 一、运行源代码所需要的依赖&#xff1a; 1、硬件支持 Windows 10&#xff0c;64位系统 2、编译器 DEV-Redpanda IDE&#xff0c;小熊猫C 二、算法实现及测试 1、C语言源程序 # define _CRT_SECURE_NO_WARNINGS # include <std…

江山易改本性难移之ZYNQ SDK FSBL加载启动代码详解

SDK版本&#xff1a;2018.3 写在前面&#xff1a; 该文档不足以使你清楚FSBL启动的寄存器级的操作细节&#xff0c;但可以让你看明白整个ZYNQ7000 FSBL代码执行的主要流程。 1. ZYNQ7000加载启动流程 &#xff08;1&#xff09;BootRom阶段为ARM上电后最早加载的代码&#x…

Android SDK环境搭建

一、Android SDK简介 SDK&#xff1a;&#xff08;software development kit&#xff09;软件开发工具包。被软件开发工程师用于为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件的开发工具的集合。 因此&#xff0c;Android SDK 指的是Android专属的软件…

【Scala】——函数式编程

1 面向对象编程和函数式编程 1.1 面向对象编程 解决问题&#xff0c;分解对象&#xff0c;行为&#xff0c;属性&#xff0c;然后通过对象的关系以及行为的调用来解决问题。 • 对象&#xff1a;用户 • 行为&#xff1a;登录、连接 JDBC、读取数据库 • 属性&#xff1a;用户…

内裤洗衣机有用吗?五款小型洗衣机全自动推荐

随着内衣洗衣机的流行&#xff0c;很多小伙伴在纠结该不该入手一款内衣洗衣机&#xff0c;专门来洗一些贴身衣物&#xff0c;答案是非常有必要的&#xff0c;因为我们现在市面上的大型洗衣机只能做清洁&#xff0c;无法对我们的贴身衣物进行一个高强度的清洁&#xff0c;而小小…

Linux运维之切换到 root 用户

春花秋月何时了,往事知多少。此付费专栏不要订阅,不要订阅,听人劝。 🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 系列专栏目录 [Java项目实战] 介绍Java…

C/C++ 位段

目录 什么是位段&#xff1f; 位段的内存分配 位段的跨平台问题 什么是位段&#xff1f; 位段的声明与结构是类似的&#xff0c;但是有两个不同&#xff1a; 位段的成员必须是 int、unsigned int 或signed int 等整型家族。位段的成员名后边有一个冒号和一个数字 这是一个…

JPEG格式详解Baseline、Progressive的区别

文章目录 JPEG的简介压缩质量/压缩比率色彩空间基线和渐进子采样存储选项 基线和渐进基线格式渐进格式&#xff1a; 子采样4:4:4&#xff08;无损&#xff09;4:2:24:2:0 JPEG的简介 JPEG&#xff08;Joint Photographic Experts Group&#xff09;是一种常见的图像压缩格式&a…

K8S 存储卷

意义&#xff1a;存储卷----数据卷 容器内的目录和宿主机的目录进行挂载 容器在系统上的生命周期是短暂的&#xff0c;delete,k8s用控制器创建的pod&#xff0c;delete相当于重启&#xff0c;容器的状态也会回复到初始状态 一旦回到初始状态&#xff0c;所有的后天编辑的文件…

原来这些小众知识库软件这么好用,挖到宝了

在企业管理中&#xff0c;知识库的作用越来越被重视。它不仅可以提高工作流程的效率&#xff0c;还可以最大限度地利用企业中的知识资源。然而&#xff0c;在众多的知识库工具中选择一款合适的并非易事。不用担心&#xff0c;今天我要为大家揭晓一些小众却非常好用的知识库软件…

C语言之详解数组【附三子棋和扫雷游戏实战】

文章目录 一、一维数组的创建和初始化1、数组的创建2、数组的初始化3、一维数组的使用4、 一维数组在内存中的存储 二、二维数组的创建和初始化1、二维数组的创建2、二维数组的初始化3、二维数组的使用4、二维数组在内存中的存储 三、数组越界边界值考虑不当导致越界访问数组大…