vlambda博客
学习文章列表

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 8:55 更新文章,每天掉亿点点头发...

源码精品专栏

 




  • 1. 概述
  • 2. Swagger Dubbo
  • 3. 接入 Knife4j 作为 Swagger UI 界面
  • 4. 接入 YApi 统一管理
  • 666. 彩蛋

1. 概述

在使用 SpringMVC 构建 HTTP API 时,我们可以通过 Swagger 自动生成 HTTP 接口文档,通过 Swagger UI 界面上进行 HTTP 接口调试。如下图所示:

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
Swagger HTTP 界面

秃头提示:对 Swagger 不太了解的胖友,可以去阅读下艿艿写的 《芋道 Spring Boot API 接口文档 Swagger 入门》 文章。

开发体验杠杠的好!但是在使用 Dubbo 构建 RPC API 时,简直想要自闭。常常面临的痛苦是:

  • 隔壁团队的老王,不肯给 Dubbo 写 接口文档,只能从他的 Dubbo API 的 jar 包中寻寻觅觅想要的接口,贼不方便~
  • 自己编写的每个 Dubbo API 接口,都需要写个 Controller 或者 Test 类去调用测试, 接口调试非常麻烦~

在一个逐步自闭到要爆炸的下午,艿艿做了一波 Dubbo 接口文档与接口调试的调研,想要尝试这块的痛点。结果比想象中顺利且简单,这不趁着这无聊到抠脚的周末,整理下分享给胖友。

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
IDEA 上号

🚀 这么良心,不考虑给艿艿点个赞么?!

芳芳都说好!!!

2. Swagger Dubbo

哈哈哈~实际上,我们还是可以通过 Swagger 实现 Dubbo 的接口文档和接口调试这两个功能。效果如下图:

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
Swagger Dubbo 界面
Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
Swagger Dubbo 项目

2.1 小小改造

dubbo-swagger 最新版本 v2.0.1,并不支持 Dubbo 2.7.0 开始的版本,因此我们需要做一点点小小的改造。具体的改造点如下:

良心艿:怕麻烦的胖友,可以看艿艿 fork 出来的仓库 https://github.com/YunaiV/swagger-dubbo,给改的明明白白了,直接能用。


    1. 合并 PR#50 的代码,支持 Dubbo 2.7.0 开始的版本。

    1. 合并 PR#46 的代码,使 Swagger UI 界面正确展示 POJO 类型的参数。

2.2 快速入门

swagger-dubbo 项目提供了 Spring Boot + Dubbo 的示例 dubbo-provider-springboot,我们来一起看一看。

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
dubbo-provider-springboot 示例

不过 dubbo-provider-springboot 示例暂时有一点点小“问题”,我们需要稍微修正下。

2.2.1 修改依赖

示例使用 Dubbo 的版本是 2.6.0,而我们希望使用 Dubbo 的版本是 2.7.0 开始,因此需要略微修改 pom.xml 如下:

<!-- 去除 Dubbo 2.6.0 的依赖 -->
<!--  <dependency>-->
<!--   <groupId>com.alibaba</groupId>-->
<!--   <artifactId>dubbo</artifactId>-->
<!--   <version>2.6.0</version>-->
<!--   <exclusions>-->
<!--    <exclusion>-->
<!--     <groupId>org.springframework</groupId>-->
<!--     <artifactId>spring</artifactId>-->
<!--    </exclusion>-->
<!--   </exclusions>-->
<!--  </dependency>-->
<!--  <dependency>-->
<!--   <groupId>org.apache.zookeeper</groupId>-->
<!--   <artifactId>zookeeper</artifactId>-->
<!--   <version>3.5.2-alpha</version>-->
<!--  </dependency>-->
<!--  <dependency>-->
<!--      <groupId>org.apache.curator</groupId>-->
<!--      <artifactId>curator-framework</artifactId>-->
<!--      <version>4.0.1</version>-->
<!--  </dependency>-->

<!-- 引入 Dubbo 2.7.0 的依赖 -->
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.7.4.1</version>
</dependency>
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>2.7.4.1</version>
</dependency>
<!-- 使用 Zookeeper 作为注册中心 -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>2.13.0</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>2.13.0</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-client</artifactId>
    <version>4.0.1</version>
</dependency>

2.2.2 修改配置文件

修改 application.properties 配置文件,增加如下配置项:

swagger.dubbo.application.groupId=com.deepoove
swagger.dubbo.application.artifactId=dubbo-provider-springboot
swagger.dubbo.application.version=2.0.2-SNAPSHOT

通过 swagger.dubbo.application 配置项,可以知道该 Dubbo 服务的 API jar 包的 groupIdartifactIdversion 信息。

友情提示:swagger-dubbo 还提供了其它配置项,一般默认即可。感兴趣的胖友,可以看看 SwaggerDubboProperties 配置类。

2.2.3 简单测试

下面,我们来运行下 dubbo-provider-springboot 示例项目,感受下 swagger-dubbo 的具体功能。

第一步,本地运行一个 ZooKeeper 服务,作为注册中心。

第二步,执行 Application 类,将 Dubbo 服务提供者进行启动。启动成功的日志如下:

14:12:24.180 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8077 (http) with context path ''
14:12:24.184 [main] INFO  c.d.d.p.springboot.Application - Started Application in 3.443 seconds (JVM running for 4.109)
Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
Swagger Dubbo 接口文档

这里,我们已经可以看到当前 Dubbo 服务所提供的 RPC 接口文档。

友情提示:访问的 Swagger UI 界面,就是我们在示例项目的 resources/static/distv2 目录下的静态资源。

第四步,我们可以任一选择一个 Dubbo API 接口,填写参数后,点击「Try it out!」按钮进行 RPC 接口调试。如下图所示:

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
Swagger Dubbo 接口调试

通过接口调试的功能,我们可以方便的测试。

友情提示:可能有胖友会好奇,swagger-dubbo 是如何实现接口调试的功能的呢?答案可以到 DubboHttpController 类中去寻找。

简单来说,就是使用 Dubbo 提供的 Java API 获得到对应 Dubbo Consumer 对象,将 HTTP 请求参数映射成 Dubbo RPC 请求参数,最终进行调用。

3. 接入 Knife4j 作为 Swagger UI 界面

由于 dubbo-swagger 项目并未将其提供的 Swagger UI 界面封装成一个 jar 包,导致集成 dubbo-swagger 的 Dubbo 项目需要在其 resources 目录下,添加相应的 Swagger UI 的静态资源。例如说:

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
Dubbo Swagger UI 界面的静态资源

显然,这么做是非常不优雅的,因为后续无法方便的更新 Swagger UI 的静态资源。那么,应该怎么办呢?这里艿艿先演示一种解决方案,也是目前团队所采用的,接入 Knife4j 作为 Swagger UI 界面。

秃头提示:Knife4j 是基于 Swagger 的增强解决方案,提供更强大的 Swagger 的功能,以及更易用的 Swagger UI 界面。

下面,我们继续在 dubbo-provider-springboot 示例项目上,进行改造接入。

3.1 修改依赖

修改 pom.xml 文件,引入 Knife4j Starter 依赖。具体如下:

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>2.0.5</version>
</dependency>

3.2 创建 SwaggerConfiguration

创建 SwaggerConfiguration 配置类,自定义 SwaggerResourcesProvider Bean。代码如下:

@Configuration
@EnableSwagger// 标记项目启用 Swagger API 接口文档
public class SwaggerConfiguration {

    @Bean
    @Primary
    public SwaggerResourcesProvider newSwaggerResourcesProvider(Environment env, DocumentationCache documentationCache) {
        return new InMemorySwaggerResourcesProvider(env, documentationCache) {

            @Override
            public List<SwaggerResource> get() {
                // 1. 调用 InMemorySwaggerResourcesProvider
                List<SwaggerResource> resources = super.get();
                // 2. 添加 swagger-dubbo 的资源地址
                SwaggerResource dubboSwaggerResource = new SwaggerResource();
                dubboSwaggerResource.setName("dubbo");
                dubboSwaggerResource.setSwaggerVersion("2.0");
                dubboSwaggerResource.setUrl("/swagger-dubbo/api-docs");
                dubboSwaggerResource.setLocation("/swagger-dubbo/api-docs"); // 即将废弃,和 url 属性等价。
                resources.add(0, dubboSwaggerResource);
                return resources;
            }

        };
    }

}

艿艿先暂时不解释为什么要这么做,因为涉及到 Swagger 运行机制相关的知识,略微有点小复杂~~稍后,在「3.4 再看 SwaggerConfiguration」小节,我们在一起遨游这块知识的海洋。

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
不想学习

3.3 简单测试

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
Knife4j Swagger UI 界面

是不是相比 swagger-dubbo 提供的 Swagger UI 界面更加优秀。

我们再来看看接口文档和接口调试的界面,如下图所示:

  • Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
    接口文档
  • Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
    接口调试

重要提示:此时,我们可以将 resources 目录下的 Swagger UI 的静态资源删除。

艿艿这里不删除的原因,还是方便大家体验对比 = =

3.4 再看 SwaggerConfiguration

为什么我们要在 SwaggerConfiguration 配置类中,自定义一个 SwaggerResourcesProvider Bean 呢?原因是,它和 Swagger UI 界面的运行机制有关。

① Swagger UI 界面采用前后端分离的架构,通过请求 Swagger 定义的接口元数据 HTTP API,获得到每个接口的信息,展示成接口文档。

可能有点难懂,我们来看看 dubbo-swagger 项目在 dubbo-provider-springboot 示例项目中,自定义实现的接口元数据 HTTP API的返回结果,如下图所示:

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
接口元数据 HTTP API
  • paths 数组中,每一个元素对应一个 接口的信息。而这些 接口的信息,是通过扫描 Swagger 的注解所获取到。

课外作业:对 dubbo-swagger 项目实现的接口元数据 HTTP API,可以后续看看 SwaggerDubboController 类的代码,比较简单。

② 在理解完 Swagger 定义的接口元数据 HTTP API 之后,再来看看 Swagger 定义的资源 HTTP API。Swagger Resource 资源的作用,用于将我们使用 SpringMVC 实现的 HTTP API 进行分组。并且,每个资源对应一个接口元数据 HTTP API,用于获取该分组的接口元数据。

可能有点懵逼,我们来看看 dubbo-provider-springboot 示例项目中,资源 HTTP API的返回结果,如下图所示:

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
资源 HTTP API
  • 蓝色部分】Swagger 默认实现了一套 Swagger 资源的逻辑,通过 InMemorySwaggerResourcesProvider 的 #get() 方法,进行获取。我们在使用 SpringMVC 实现的 HTTP API 接口,就属于该 Swagger 资源。
  • 红色部分swagger-dubbo 自定义了一套 Swagger 资源的逻辑,所以我们需要 手动添加一个名字为 dubbo 的 Swagger Resource 分组,集成到 Swagger 体系中。

现在,胖友是不是能够理解 SwaggerConfiguration 配置类的作用了。

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
重看 Knife4j Swagger UI 界面

可能胖友会有一个疑惑,为什么我们在使用 swagger-dubbo 提供的 Swagger UI 界面时,不用创建 SwaggerConfiguration 配置类呢?因为它不考虑存在多 Swagger Resource 资源的情况,直接请求 swagger-dubbo 提供的接口元数据 HTTP API。如下图所示:

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
重看 swagger-dubbo Swagger UI 界面 Swagger UI 界面

3.5 其它解决方案

除了接入 Knife4j 作为 Swagger UI 界面的方案外,还有两种方案:

方案一,将 swagger-dubbo 提供的 Swagger UI 的静态资源,部署到 Nginx 下。这样,我们就可以访问 Nginx 下的 Swagger UI 界面,填写需要查看 Dubbo 服务的接口元数据 HTTP API 即可。如下图所示:

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
swagger-dubbo` Swagger UI 界面 Swagger UI 界面

方案二,将 swagger-dubbo 提供的 Swagger UI 的静态资源,打包成名字为 swagger-dubbo-uijar 包。这样,每个 Dubbo 服务提供者的项目,引入该 jar 包即可。具体可参考 Knife4j 的 knife4j-spring-ui 的做法,如下图所示:

Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
knife4j-spring-ui

4. 接入 YApi 统一管理

随着 Dubbo 服务越来越多,我们需要一个 API 平台能够查看到所有的 Dubbo 服务的 RPC API 接口信息。目前,艿艿比较推荐和使用的 YApi 平台,主要原因是 YApi 可以采集 Swagger 提供的接口元数据 HTTP API,自动进行同步接口信息的同步。

秃头提示:对 YApi 不太了解的胖友,可以去阅读下艿艿写的 《芋道 Spring Boot API 接口文档 Swagger 入门》 的「4. 更强大的 YApi」小节。

具体的效果,胖友可以看看如下图:

  • Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
    项目列表
  • Swagger 自动生成 Dubbo 服务的接口文档,以及测试调用
    项目详情

dubbo-swagger 提供的接口元数据 HTTP API,路径是 /swagger-dubbo/api-docs。至于如何配置定时采集,可参考如下图:

定时采集

666. 彩蛋

至此,我们通过多个开源项目的组合,实现 Dubbo 的接口文档和接口调试的功能。简单来总结下:

  • 基于 Swagger Dubbo 项目,实现 Dubbo RPC API 的 接口文档和 接口调试的功能。
  • 基于 Knife4j 项目,提供更强大的 Dubbo Swagger UI 界面。
  • 基于 YApi 项目,作为统一的 API 管理平台,可以查看 所有 Dubbo 项目的 API 接口文档、进行 接口调试。

当然,如果我们要将该方案落地到公司的 Dubbo 项目中,还有一些事情需要去做:

  • 1、将修改后的 dubbo-swagger 项目,重新编译打包,推送到公司的 Nexus 私服。毕竟,咱也不知道 dubbo-swagger 项目啥时候会支持 Dubbo 2.7.0 开始的版本。
  • 2、编写公司的 Swagger Dubbo Starter,将对 Knife4j 的整合进行自动配置。
  • 3、尝试基于 YApi 提供的 mock 功能,实现 Dubbo 服务的 mock 能力,以便更好的并行开发。

End~继续抠脚。

我是艿艿,一个每天徘徊在煞笔与牛啤的死胖子。




已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 20 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

兄弟,一口,点个👇