Spring Cloud Gateway集成SpringDoc,集中管理微服务API

news2024/11/26 5:59:31

本文目标

Spring Cloud微服务集成SpringDoc,在Spring Cloud Gateway中统一管理微服务的API,微服务上下线时自动刷新SwaggerUi中的group组。

依赖版本

框架版本
Spring Boot3.1.5
Spring Cloud2022.0.4
Spring Cloud Alibaba2022.0.0.0
Spring Doc2.2.0
Nacos Server2.2.3

开始集成

项目模块

image.png

公共模块里的配置是之前文章中提到的内容,加了一个webmvc和webflux的适配,我会将文章和代码仓库的链接放在最下边,有需要的可以去看看。

引入依赖,配置依赖管理

在父模块中添加lombok、测试包和服务发现与注册的包,管理Spring Cloud、Spring Cloud Alibaba依赖版本,如下
不要忘了SpringDoc的依赖管理

<?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.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>spring-doc-spring-cloud</artifactId>
    <version>0.0.1</version>
    <packaging>pom</packaging>
    <name>spring-doc-spring-cloud</name>
    <description>spring-doc-spring-cloud</description>
    <modules>
        <module>spring-doc-cloud-common</module>
        <module>spring-doc-cloud-gateway</module>
        <module>spring-doc-cloud-webflux</module>
        <module>spring-doc-cloud-webmvc</module>
    </modules>
    <properties>
        <!-- 指定Java版本为Java17 -->
        <java.version>17</java.version>
        <!-- 公共模块版本 -->
        <common.version>0.0.1</common.version>
        <!-- 修复SpringBoot自带snakeyaml依赖版本的漏洞 -->
        <snakeyaml.version>2.0</snakeyaml.version>
        <!-- SpringDoc-OpenApi版本号 -->
        <spring-doc.version>2.2.0</spring-doc.version>
        <!-- SpringCloud版本 -->
        <spring-cloud.version>2022.0.4</spring-cloud.version>
        <!-- 指定打包插件版本 -->
        <maven-surefire-plugin.version>3.2.2</maven-surefire-plugin.version>
        <!-- Spring Cloud Alibaba版本号 -->
        <spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version>
    </properties>
    <dependencies>
        <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>
        <!-- 服务注册与发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </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>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- 适用于webmvc的SpringDoc依赖 -->
            <dependency>
                <groupId>org.springdoc</groupId>
                <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
                <version>${spring-doc.version}</version>
            </dependency>

            <!-- 适用于webflux的SpringDoc依赖 -->
            <dependency>
                <groupId>org.springdoc</groupId>
                <artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
                <version>${spring-doc.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

spring-doc-cloud-gateway模块说明

引入webflux、gateway、loadbalancer负载均衡和springdoc依赖,同时引入公共模块

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.example</groupId>
        <artifactId>spring-doc-spring-cloud</artifactId>
        <version>0.0.1</version>
    </parent>

    <artifactId>spring-doc-cloud-gateway</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- webflux依赖 -->
        <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>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

        <!-- SpringDoc -->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
        </dependency>

        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 公共包,这里是对于swagger的自定义配置,可以参考之前的文章或直接查看代码仓库的实现 -->
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>spring-doc-cloud-common</artifactId>
            <version>${common.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <image>
                        <builder>paketobuildpacks/builder-jammy-tiny:latest</builder>
                    </image>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

修改application.yml

开启gateway自动扫描,根据注册中心的服务自动生成路由,路由名转小写,添加自定义的swagger配置。

spring:
  application:
    name: gateway
  cloud:
    gateway:
      discovery:
        locator:
          # 根据注册中心的服务自动生成路由
          enabled: true
          # 路由名转小写
          lower-case-service-id: true

# ------------以下内容可改为公共配置------------
# SpringDoc自定义配置
custom:
  info:
    title: ${spring.application.name}-api
    version: 0.0.1
    description: 这是一个使用SpringDoc生成的在线文档.
    terms-of-service: http://127.0.0.1:8000/test01
    gateway-url: http://127.0.0.1:8080
  license:
    name: Apache 2.0
  security:
    name: Authenticate
    token-url: http://kwqqr48rgo.cdhttp.cn/oauth2/token
    authorization-url: http://kwqqr48rgo.cdhttp.cn/oauth2/authorize

添加InstancesChangeEventListener

监听微服务启、停状态,微服务状态改变后刷新Swagger UI中的组。

package com.example.config;

import com.alibaba.nacos.client.naming.event.InstancesChangeEvent;
import com.alibaba.nacos.common.notify.Event;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.notify.listener.Subscriber;
import com.alibaba.nacos.common.utils.JacksonUtils;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.properties.AbstractSwaggerUiConfigProperties;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static org.springdoc.core.utils.Constants.DEFAULT_API_DOCS_URL;
import static org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier.SERVICE_INSTANCE_CACHE_NAME;

/**
 * 监听注册中心实例注册状态改变事件,微服务实例状态改变后刷新swagger ui的组(一个组等于一个微服务)
 * 
 * @author vains
 */
@Slf4j
@Configuration(proxyBeanMethods = false)
public class InstancesChangeEventListener extends Subscriber<InstancesChangeEvent> {

    private final String LB_SCHEME = "lb";

    private final RouteDefinitionLocator locator;

    @Resource
    private CacheManager defaultLoadBalancerCacheManager;

    private final SwaggerUiConfigProperties swaggerUiConfigProperties;

    /**
     * 获取配置文件中默认配置的swagger组
     */
    private final Set<AbstractSwaggerUiConfigProperties.SwaggerUrl> defaultUrls;


    public InstancesChangeEventListener(RouteDefinitionLocator locator,
                                        SwaggerUiConfigProperties swaggerUiConfigProperties) {
        this.locator = locator;
        this.swaggerUiConfigProperties = swaggerUiConfigProperties;
        // 构造器中初始化配置文件中的swagger组
        this.defaultUrls = swaggerUiConfigProperties.getUrls();
    }

    @Override
    public void onEvent(InstancesChangeEvent event) {
        if (log.isDebugEnabled()) {
            log.info("Spring Gateway 接收实例刷新事件:{}, 开始刷新缓存", JacksonUtils.toJson(event));
        }
        Cache cache = defaultLoadBalancerCacheManager.getCache(SERVICE_INSTANCE_CACHE_NAME);
        if (cache != null) {
            cache.evict(event.getServiceName());
        }
        // 刷新group
        this.refreshGroup();

        if (log.isDebugEnabled()) {
            log.info("Spring Gateway 实例刷新完成");
        }
    }

    /**
     * 刷新swagger的group
     */
    public void refreshGroup() {
        // 获取网关路由
        List<RouteDefinition> definitions = locator.getRouteDefinitions().collectList().block();
        if (ObjectUtils.isEmpty(definitions)) {
            return;
        }

        // 根据路由规则生成 swagger组 配置
        Set<AbstractSwaggerUiConfigProperties.SwaggerUrl> swaggerUrls = definitions.stream()
                // 只处理在注册中心注册过的(lb://service)
                .filter(definition -> definition.getUri().getScheme().equals(LB_SCHEME))
                .map(definition -> {
                    // 生成 swagger组 配置,以微服务在注册中心中的名字当做组名、请求路径(我这里使用的是自动扫描生成的,所以直接用了这个,其它自定义的按需修改)
                    String authority = definition.getUri().getAuthority();
                    return new AbstractSwaggerUiConfigProperties.SwaggerUrl(authority, authority + DEFAULT_API_DOCS_URL, authority);
                })
                .collect(Collectors.toSet());

        // 如果在配置文件中有添加其它 swagger组 配置则将两者合并
        if (!ObjectUtils.isEmpty(defaultUrls)) {
            swaggerUrls.addAll(defaultUrls);
        }

        // 重置配置文件
        swaggerUiConfigProperties.setUrls(swaggerUrls);

        if (log.isDebugEnabled()) {
            String groups = swaggerUrls.stream()
                    .map(AbstractSwaggerUiConfigProperties.SwaggerUrl::getName)
                    .collect(Collectors.joining(","));
            log.debug("刷新Spring Gateway Doc Group成功,获取到组:{}.", groups);
        }
    }

    @PostConstruct
    public void registerToNotifyCenter() {
        // 注册监听事件
        NotifyCenter.registerSubscriber((this));
    }

    @Override
    public Class<? extends Event> subscribeType() {
        return InstancesChangeEvent.class;
    }
}

网关启动时、微服务停止、微服务启动时网关会从注册中心获取最新的服务列表,然后根据服务列表生成路由配置,路由的代理路径就是微服务的名字,使用http://网关ip:网关端口/微服务名/**访问对应的微服务。

在注册中心(Nacos)的服务列表更新时会有一个SpringEvent事件通知,也就是上边类中的监听实现,每次收到通知时就会根据网关的路由生成SwaggerUrl列表,其中name是微服务的名字(application.name),路径是/{application.name}/v3/api-docs,这样实际上就是通过网关将请求代理至各微服务了,获取到的api信息实际上也是各微服务的,如果某个微服务禁用swagger,在网关中也获取不到对应的api信息。以上内容就是之前提到的微服务状态改变后刷新Swagger UI中的组。

当然,虽然可以通过网关代理获取到微服务的api信息,但是在测试接口时还是会出现问题,请求会直接发送至微服务,并不会经过网关代理,如下所示

image.png

image.png

所以说需要修改各微服务配置,指定当前服务访问的url,在SpringDoc配置中添加servers属性,并设置值为被网关代理的路径,如下所示

image.png

在引用的微服务中设置自定义配置custom.info.gateway-url,相信看到这里就明白为什么上方网关的yml中会有这么一个配置了。

修改微服务yml

添加类似如下配置,设置spring.application.name,设置SpringDoc自定义配置,设置custom.info.gateway-url

spring:
  application:
    name: webmvc

# ------------以下内容可改为公共配置------------
# SpringDoc自定义配置
custom:
  info:
    title: ${spring.application.name}-api
    version: 0.0.1
    description: 这是一个使用SpringDoc生成的在线文档.
    terms-of-service: http://127.0.0.1:8200/test01
    # 设置当前服务在网关中的代理路径
    gateway-url: http://127.0.0.1:8080/${spring.application.name}
  license:
    name: Apache 2.0
  security:
    name: Authenticate
    token-url: http://kwqqr48rgo.cdhttp.cn/oauth2/token
    authorization-url: http://kwqqr48rgo.cdhttp.cn/oauth2/authorize
server:
  port: 8200

查看效果

webflux访问地址,默认会有一个webjars前缀

http://127.0.0.1:8080/webjars/swagger-ui/index.html

image.png

其它微服务都是一些测试接口,没必要贴了,大家用自己的就好,或者去代码仓库拉取代码看看。

附录

  1. SpringDoc枚举字段处理与SpringBoot接收枚举参数处理
  2. SpringDoc基础配置和集成OAuth2登录认证教程
  3. 代码仓库:Gitee、Github

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

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

相关文章

老师怎么选班干部

对于老师来说&#xff0c;选择合适的班干部是一项重要任务。班干部不仅是学生的榜样&#xff0c;也是班级秩序维护者。 了解学生的情况是必要的。老师需要了解每个学生的性格、能力和潜力&#xff0c;为他们分配适合的职务。对于新班级&#xff0c;可以观察学生在课堂上的表现、…

【古月居《ros入门21讲》学习笔记】12_服务端Server的编程实现

目录 说明&#xff1a; 1. 服务模型 说明 2. 实现过程&#xff08;C&#xff09; 创建服务器代码&#xff08;C&#xff09; 配置服务器代码编译规则 编译 运行 3. 实现过程&#xff08;Python&#xff09; 创建服务器代码&#xff08;Python&#xff09; 运行效果 说…

人民的艺术家王昱玺出席巴基斯坦驻华使馆学校国际文化日活动

王昱玺和罗马尼亚驻华大使馆特命全权大使丹-霍利亚马克西姆 王昱玺&#xff0c;出生于抗日革命根据地山西省吕梁市。联合国金砖国家文化理事会外交官大使、安徒生世界妇女贵族天使、世界文联和平大使、世界文化大使勋章获得者、中国内地女高音歌唱演员、中央电视台CCTV艺术传…

推荐6款交互设计软件,助你事半功倍!

交互软件可以帮助设计师从“可用性”和“用户体验”的角度优化他们的作品。如果设计师想创建一个令人满意的交互设计作品&#xff0c;一个方便的交互设计软件是必不可少的。当然&#xff0c;交互软件只是我们实现目标的一种手段。根据设计师的个人喜好和方便&#xff0c;选择易…

气膜建筑助力体育场馆快速普及

传统的室内体育馆投入资金庞大&#xff0c;建设强度高&#xff0c;建设周期漫长。而气膜体育馆的出现&#xff0c;不仅显著降低了建设成本和缩短了建设周期&#xff0c;更符合节能环保的需求&#xff0c;成为推动场馆快速普及的创新建筑形式。 对于校园设施的建设而言&#xff…

第二十章多线程总结

20.1 线程简介 世间有很多工作都是可以同时完成的。例如&#xff0c;人体可以同时进行呼吸、血液循环、思考问题等活用户既可以使用计算机听歌&#xff0c;也可以使用它打印文件。同样&#xff0c;计算机完全可以将多种活动同时进这种思想放在 Java 中被称为并发&#xff0c;而…

【论文笔记】SDCL: Self-Distillation Contrastive Learning for Chinese Spell Checking

文章目录 论文信息Abstract1. Introduction2. Methodology2.1 The Main Model2.2 Contrastive Loss2.3 Implementation Details(Hyperparameters) 3. Experiments代码实现个人总结值得借鉴的地方 论文信息 论文地址&#xff1a;https://arxiv.org/pdf/2210.17168.pdf Abstrac…

与 PCIe 相比,CXL为何低延迟高带宽?

文章目录 前言1. LatencyPCIE 生产者消费则模型结论Flit 包PCIE/CXL.ioCXL.cace & .mem总结 2. BandWidth常见开销CXL.IO Link efficiencyPCIe Link efficiencyCXL.IO bandwidthCXL.mem/.cache bandwidth 参考 前言 CXL 规范里没有具体描述与PCIe 相比低延时高带宽的原因&…

Ros报错:The Plugin for class ‘jsk_rviz_plugin/Plotter2D‘ failed to load

一般出现这种情况&#xff0c;是提醒Ros缺少某种库&#xff1a; 图中显示的错误是说明少了jsk_rviz_plugins库&#xff0c;他是一个提供原始rviz插件的包。 解决办法是安装相应的库与插件&#xff1a; #根据自己ROS的版本选择相应的指令 # ubuntu20.04:noetic sudo apt-get i…

Django快速搭建静态网页

Django的快速搭建 这个是例子 这个是一个目录 项目名称&#xff1a;项目似乎被命名为DJ0928&#xff0c;这是Django项目的根目录。 文件都是Django项目的核心配置文件。 settings.py 包含了项目的配置设置。urls.py 定义了项目的URL路由。wsgi.py 和 asgi.py 分别用于Web服务器…

Java高级技术(反射:获取类的成员变量)

一&#xff0c;获取类的成员变量的常用方法 二&#xff0c;案例 三&#xff0c;赋值&#xff0c;取值的常用方法 四&#xff0c; 案例 五&#xff0c;获取类的成员方法的常用方法 六&#xff0c;案例 七&#xff0c;执行 八&#xff0c;案例

代码随想录算法训练营 ---第五十天

第一题&#xff1a; 简介&#xff1a; 做买卖股票的问题最重要的是分析状态&#xff0c;将状态分析清楚本题也就做出来了。我们看本题它说我们至多可以完成两笔交易&#xff0c;也就意味着我们有两种选择 dp状态分析 1.完成一次交易获得最大利益 完成一次交易我们用二维数组…

零代码连接钉钉宜搭与用友U8,让业财数据管理简单高效

零代码连接钉钉宜搭与用友U8&#xff0c;让业财数据管理简单高效 如果把企业内部的业务系统比作一条条河流&#xff0c;那么它们的交汇点就像江河湖海。在这些交汇点上&#xff0c;数据的汇集、分析和共享离不开系统之间的集成。 钉钉宜搭和用友U8是两个在企业中非常重要的系统…

智慧工地信息化管理系统源码带APP

需求痛点&#xff1a;建筑行业是一个安全事故多发的行业。目前&#xff0c;工程建设规模不断扩大&#xff0c;工艺流程纷繁复杂&#xff0c;如何搞好现场施工现场管理&#xff0c;控制事故发生频率&#xff0c;一直是施工企业、政府管理部门关注的焦点。利用现代科技&#xff0…

1145. 北极通讯网络(Kruskal,并查集维护)

北极的某区域共有 n 座村庄&#xff0c;每座村庄的坐标用一对整数 (x,y) 表示。 为了加强联系&#xff0c;决定在村庄之间建立通讯网络&#xff0c;使每两座村庄之间都可以直接或间接通讯。 通讯工具可以是无线电收发机&#xff0c;也可以是卫星设备。 无线电收发机有多种不…

哈希思想应用【C++】(位图,布隆过滤器,海量数据处理面试题)

目录 一&#xff0c;位图 1. 位图概念 2.实现 3. 测试题 位图的优缺点 二&#xff0c;布隆过滤器 1). 布隆过滤器提出 2). 概念 3). 布隆过滤器的查找 4). 布隆过滤器删除(了解) 5). 布隆过滤器优点 6). 布隆过滤器缺陷 三&#xff0c;海量数据面试题 1&#xff…

通过网易的API完成一个简易的音乐播放器

效果图 工程环境 1、使用node在本地部署网易云音乐API接口 下载解压 链接:https://pan.baidu.com/s/1YQiMJoUMEYlMz14FH5xxRA?pwd36o5 提取码:36o5 工程目录概览 &#xff08;js文件夹里面放了music.html和main.js和vue.js&#xff09; 工程目录)&#xff08;有点重复…

ubuntu16.04部署gitlab-runner触发gitlab流水线

环境&#xff1a;ubuntu16.04 gitlab服务器&#xff1a;192.168.1.12 runner服务器&#xff1a;192.168.1.11 1.下载 环境&#xff1a;192.168.1.11 cd /usr/local/srcwget https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_amd64.debsudo dpkg …

【新手解答1】深入探索 C 语言:变量名、形参 + 主调函数、被调函数 + 类和对象 + 源文件(.c 文件)、头文件(.h 文件)+ 库

C语言的相关问题解答 写在最前面目录 问题1变量名与变量的关系与区别变量和数据类型形参&#xff08;形式参数&#xff09;的概念 问题2解析&#xff1a;主调函数和被调函数延伸解析&#xff1a;主调函数对于多文件程序的理解总结 问题3类和对象变量和数据类型变量是否为抽象的…

带大家做一个,易上手的家常蒜薹炒瘦肉

首先 从冰箱那一块瘦肉 用水化一下冰 然后 那一把蒜薹 将所有蒜薹头和尾部去掉一小节 这个地方是不能吃的 然后 剩下的部分 切成如下图这样 一小条一小条的样子 然后 将蒜薹倒入盆中清水洗一下 瘦肉清洗一下 然后切片 然后 直接起锅烧油 油烧热后马上下肉翻炒 一定要大点翻…