本文目標(biāo)
Spring Cloud微服務(wù)集成SpringDoc,在Spring Cloud Gateway中統(tǒng)一管理微服務(wù)的API,微服務(wù)上下線時自動刷新SwaggerUi中的group組。
依賴版本
框架 | 版本 |
---|---|
Spring Boot | 3.1.5 |
Spring Cloud | 2022.0.4 |
Spring Cloud Alibaba | 2022.0.0.0 |
Spring Doc | 2.2.0 |
Nacos Server | 2.2.3 |
開始集成
項(xiàng)目模塊
公共模塊里的配置是之前文章中提到的內(nèi)容,加了一個webmvc和webflux的適配,我會將文章和代碼倉庫的鏈接放在最下邊,有需要的可以去看看。
引入依賴,配置依賴管理
在父模塊中添加lombok、測試包和服務(wù)發(fā)現(xiàn)與注冊的包,管理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>
<!-- 修復(fù)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>
<!-- 服務(wù)注冊與發(fā)現(xiàn) -->
<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負(fù)載均衡和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>
<!-- 網(wǎng)關(guān) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 負(fù)載均衡 -->
<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的自定義配置,可以參考之前的文章或直接查看代碼倉庫的實(shí)現(xiàn) -->
<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自動掃描,根據(jù)注冊中心的服務(wù)自動生成路由,路由名轉(zhuǎn)小寫,添加自定義的swagger配置。
spring:
application:
name: gateway
cloud:
gateway:
discovery:
locator:
# 根據(jù)注冊中心的服務(wù)自動生成路由
enabled: true
# 路由名轉(zhuǎn)小寫
lower-case-service-id: true
# ------------以下內(nèi)容可改為公共配置------------
# 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
監(jiān)聽微服務(wù)啟、停狀態(tài),微服務(wù)狀態(tài)改變后刷新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;
/**
* 監(jiān)聽注冊中心實(shí)例注冊狀態(tài)改變事件,微服務(wù)實(shí)例狀態(tài)改變后刷新swagger ui的組(一個組等于一個微服務(wù))
*
* @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;
/**
* 獲取配置文件中默認(rèn)配置的swagger組
*/
private final Set<AbstractSwaggerUiConfigProperties.SwaggerUrl> defaultUrls;
public InstancesChangeEventListener(RouteDefinitionLocator locator,
SwaggerUiConfigProperties swaggerUiConfigProperties) {
this.locator = locator;
this.swaggerUiConfigProperties = swaggerUiConfigProperties;
// 構(gòu)造器中初始化配置文件中的swagger組
this.defaultUrls = swaggerUiConfigProperties.getUrls();
}
@Override
public void onEvent(InstancesChangeEvent event) {
if (log.isDebugEnabled()) {
log.info("Spring Gateway 接收實(shí)例刷新事件:{}, 開始刷新緩存", 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 實(shí)例刷新完成");
}
}
/**
* 刷新swagger的group
*/
public void refreshGroup() {
// 獲取網(wǎng)關(guān)路由
List<RouteDefinition> definitions = locator.getRouteDefinitions().collectList().block();
if (ObjectUtils.isEmpty(definitions)) {
return;
}
// 根據(jù)路由規(guī)則生成 swagger組 配置
Set<AbstractSwaggerUiConfigProperties.SwaggerUrl> swaggerUrls = definitions.stream()
// 只處理在注冊中心注冊過的(lb://service)
.filter(definition -> definition.getUri().getScheme().equals(LB_SCHEME))
.map(definition -> {
// 生成 swagger組 配置,以微服務(wù)在注冊中心中的名字當(dāng)做組名、請求路徑(我這里使用的是自動掃描生成的,所以直接用了這個,其它自定義的按需修改)
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() {
// 注冊監(jiān)聽事件
NotifyCenter.registerSubscriber((this));
}
@Override
public Class<? extends Event> subscribeType() {
return InstancesChangeEvent.class;
}
}
網(wǎng)關(guān)啟動時、微服務(wù)停止、微服務(wù)啟動時網(wǎng)關(guān)會從注冊中心獲取最新的服務(wù)列表,然后根據(jù)服務(wù)列表生成路由配置,路由的代理路徑就是微服務(wù)的名字,使用http://網(wǎng)關(guān)ip:網(wǎng)關(guān)端口/微服務(wù)名/**
訪問對應(yīng)的微服務(wù)。
在注冊中心(Nacos)的服務(wù)列表更新時會有一個SpringEvent事件通知,也就是上邊類中的監(jiān)聽實(shí)現(xiàn),每次收到通知時就會根據(jù)網(wǎng)關(guān)的路由生成SwaggerUrl
列表,其中name是微服務(wù)的名字(application.name),路徑是/{application.name}/v3/api-docs
,這樣實(shí)際上就是通過網(wǎng)關(guān)將請求代理至各微服務(wù)了,獲取到的api信息實(shí)際上也是各微服務(wù)的,如果某個微服務(wù)禁用swagger,在網(wǎng)關(guān)中也獲取不到對應(yīng)的api信息。以上內(nèi)容就是之前提到的微服務(wù)狀態(tài)改變后刷新Swagger UI中的組。
當(dāng)然,雖然可以通過網(wǎng)關(guān)代理獲取到微服務(wù)的api信息,但是在測試接口時還是會出現(xiàn)問題,請求會直接發(fā)送至微服務(wù),并不會經(jīng)過網(wǎng)關(guān)代理,如下所示
所以說需要修改各微服務(wù)配置,指定當(dāng)前服務(wù)訪問的url,在SpringDoc配置中添加servers
屬性,并設(shè)置值為被網(wǎng)關(guān)代理的路徑,如下所示
在引用的微服務(wù)中設(shè)置自定義配置custom.info.gateway-url
,相信看到這里就明白為什么上方網(wǎng)關(guān)的yml中會有這么一個配置了。
修改微服務(wù)yml
添加類似如下配置,設(shè)置spring.application.name
,設(shè)置SpringDoc自定義配置,設(shè)置custom.info.gateway-url
spring:
application:
name: webmvc
# ------------以下內(nèi)容可改為公共配置------------
# SpringDoc自定義配置
custom:
info:
title: ${spring.application.name}-api
version: 0.0.1
description: 這是一個使用SpringDoc生成的在線文檔.
terms-of-service: http://127.0.0.1:8200/test01
# 設(shè)置當(dāng)前服務(wù)在網(wǎng)關(guān)中的代理路徑
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訪問地址,默認(rèn)會有一個webjars
前綴
http://127.0.0.1:8080/webjars/swagger-ui/index.html
文章來源:http://www.zghlxwxcb.cn/news/detail-861122.html
其它微服務(wù)都是一些測試接口,沒必要貼了,大家用自己的就好,或者去代碼倉庫拉取代碼看看。文章來源地址http://www.zghlxwxcb.cn/news/detail-861122.html
附錄
- SpringDoc枚舉字段處理與SpringBoot接收枚舉參數(shù)處理
- SpringDoc基礎(chǔ)配置和集成OAuth2登錄認(rèn)證教程
- 代碼倉庫:Gitee、Github
到了這里,關(guān)于Spring Cloud Gateway集成SpringDoc,集中管理微服務(wù)API的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!