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

本文目标

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: gatewaycloud:gateway:discovery:locator:# 根据注册中心的服务自动生成路由enabled: true# 路由名转小写lower-case-service-id: true# ------------以下内容可改为公共配置------------
# SpringDoc自定义配置
custom:info:title: ${spring.application.name}-apiversion: 0.0.1description: 这是一个使用SpringDoc生成的在线文档.terms-of-service: http://127.0.0.1:8000/test01gateway-url: http://127.0.0.1:8080license:name: Apache 2.0security:name: Authenticatetoken-url: http://kwqqr48rgo.cdhttp.cn/oauth2/tokenauthorization-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;@Resourceprivate 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();}@Overridepublic 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());}// 刷新groupthis.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);}}@PostConstructpublic void registerToNotifyCenter() {// 注册监听事件NotifyCenter.registerSubscriber((this));}@Overridepublic 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}-apiversion: 0.0.1description: 这是一个使用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.0security:name: Authenticatetoken-url: http://kwqqr48rgo.cdhttp.cn/oauth2/tokenauthorization-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.hqwc.cn/news/231834.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CDC with Async FIFO

https://zipcpu.com/blog/2018/07/06/afifo.html

Lambda表达式与方法引用

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 引子 先来看一个案例 …

MES管理系统在智能工厂建设中的五个核心作用

随着制造业的数字化转型&#xff0c;智能工厂已经成为了现代工业生产的标志。而在智能工厂中&#xff0c;MES生产管理系统扮演着至关重要的角色。MES管理系统是一种用于管理和监控生产过程的软件系统&#xff0c;通过集成生产计划、资源调度、设备控制、质量管理等功能&#xf…

php爬虫实现把目标页面变成自己的网站页面

最近又被烦的不行&#xff0c;琐事不断&#xff0c;要是比起懒来一个人比一个人懒&#xff0c;但是懒要转换成动力啊&#xff0c;能让自己真正的偷懒&#xff0c;而不是浪费时间。每天还是需要不断的学习的&#xff0c;才能更好的提高效率&#xff0c;把之前做的简单小功能爬虫…

使用JMeter+Grafana+Influxdb搭建可视化性能测试监控平台

【背景说明】 使用jmeter进行性能测试时&#xff0c;工具自带的查看结果方式往往不够直观和明了&#xff0c;所以我们需要搭建一个可视化监控平台来完成结果监控&#xff0c;这里我们采用三种JMeterGrafanaInfluxdb的方法来完成平台搭建 【实现原理】 通过influxdb数据库存储…

【LeetCode刷题笔记】160.相交链表

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多算法知识专栏&#xff1a;算法分析&#x1f525; 给大家跳段街舞感谢…

GAN:PacGAN-生成对抗网络中两个样本的威力

论文&#xff1a;https://arxiv.org/pdf/1712.04086.pdf 代码&#xff1a;GitHub - fjxmlzn/PacGAN: [NeurIPS 2018] [JSAIT] PacGAN: The power of two samples in generative adversarial networks 发表&#xff1a;2016 一、摘要 1&#xff1a;GAN最重大的缺陷是&#xf…

Linux系统centos7防火墙firewall开放IP及端口命令

CentOS7使用的是firewall防火墙&#xff0c;不再是原来的iptables 防火墙基础命令 1&#xff1a;查看firewall防火墙状态 firewall-cmd --state //或 systemctl status firewalld2&#xff1a;打开防火墙 systemctl start firewalld3&#xff1a;关闭防火墙 systemctl sto…

Git——Git应用入门

将会介绍以下知识&#xff1a; 搭建Git环境和创建Git版本库&#xff08;init、clone&#xff09;。文件添加、状态检查、创建注释和查看历史记录。与其他Git版本库交互&#xff08;pull、push&#xff09;。解决合并冲突。创建分支列表、列表切换和合并。创建标签。 1、版本控…

虹科分享 | 平衡速度和优先级:为多样化的实时需求打造嵌入式网络(4)——从理论到实践:CANopen源代码配置

正如前文所述&#xff0c;CANopen的适应性在满足实时应用需求方面发挥着至关重要的作用。本系列文章的最后一部分将向您展示 CANopen 源代码配置的技术细节&#xff0c;以及实现高效实时性能的优化方法。 前文回顾&#xff1a; 虹科分享 | 平衡速度和优先级&#xff1a;为多样…

LaTeX插入裁剪后的pdf图像

画图 VSCode Draw.io Integration插件 有数学公式的打开下面的选项&#xff1a; 导出 File -> Export -> .svg导出成svg格式的文件。然后用浏览器打开svg文件后CtrlP选择另存为PDF&#xff0c;将图片存成pdf格式。 裁剪 只要安装了TeXLive&#xff0c;就只需要在图…

MySQL 插入数据报错 Incorrect string value

当在sys_dict_data表中执行插入语句&#xff1b; insert into sys_dict_data values(1, 1, 男, 0, sys_user_sex, , , Y, 0, admin, sysdate(), , null, 性别男);报错信息如下&#xff1a; insert into sys_dict_data values(1, 1, 男, …