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 HTTP 界面

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

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

  • 隔壁团队的老王,不肯给 Dubbo 写接口文档,只能从他的 Dubbo API 的 jar 包中寻寻觅觅想要的接口,贼不方便~

  • 自己编写的每个 Dubbo API 接口,都需要写个 Controller 或者 Test 类去调用测试,接口调试非常麻烦~

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

IDEA 上号

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

芳芳都说好!!!

2. Swagger Dubbo

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

Swagger Dubbo 界面

Swagger 对 Dubbo 的支持,是通过 swagger-dubbo 项目所实现,其 Github 地址是 https://github.com/Sayi/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,我们来一起看一看。

    dubbo-provider-springboot 示例

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

    良心艿:怕麻烦的胖友,可以直接看艿艿修改后的示例地址 https://github.com/YunaiV/swagger-dubbo/blob/master/swagger-dubbo/。

    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)
    

    第三步,使用浏览器访问 http://127.0.0.1:8077/distv2/index.html 地址,进入 swagger-dubbo 提供的 Swagger UI 界面,如下图所示:

    Swagger Dubbo 接口文档

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

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

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

    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 的静态资源。例如说:

    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
    @EnableSwagger2 // 标记项目启用 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」小节,我们在一起遨游这块知识的海洋。

    不想学习

    3.3 简单测试

    下面,我们重新运行下 dubbo-provider-springboot 示例项目,感受下 Knife4j 提供的 Swagger UI 界面。重启后,使用浏览器访问 http://127.0.0.1:8077/doc.html 地址,进行访问。如下图所示:

    Knife4j Swagger UI 界面

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

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

    • 接口文档
    • 接口调试

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

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

    3.4 再看 SwaggerConfiguration

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

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

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

    接口元数据 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的返回结果,如下图所示:

    资源 HTTP API
    • 蓝色部分】Swagger 默认实现了一套 Swagger 资源的逻辑,通过 InMemorySwaggerResourcesProvider 的 #get() 方法,进行获取。我们在使用 SpringMVC 实现的 HTTP API 接口,就属于该 Swagger 资源。

    • 红色部分swagger-dubbo 自定义了一套 Swagger 资源的逻辑,所以我们需要手动添加一个名字为 dubbo 的 Swagger Resource 分组,集成到 Swagger 体系中。

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

    ③ 我们再使用浏览器访问 http://127.0.0.1:8077/doc.html 地址,进一步感受与理解。如下图所示:

    重看 Knife4j Swagger UI 界面

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

    重看 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 UI 界面 Swagger UI 界面

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

    knife4j-spring-ui

    4. 接入 YApi 统一管理

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

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

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

    • 项目列表
    • 项目详情

    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 行代码的电商微服务项目。

    获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

    兄弟,一口,点个!????


版权声明:本文为github_38592071原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。