《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 http://www.iocoder.cn/Dubbo/Swagger/ 「芋道源码」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

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 示例暂时有一点点小“问题”,我们需要稍微修正下。

良心艿:怕麻烦的胖友,可以直接看艿艿修改后的示例地址 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 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 的做法,如下图所示:

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~继续抠脚。

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

文章目录
  1. 1. 1. 概述
  2. 2. 2. Swagger Dubbo
    1. 2.1. 2.1 小小改造
    2. 2.2. 2.2 快速入门
      1. 2.2.1. 2.2.1 修改依赖
      2. 2.2.2. 2.2.2 修改配置文件
      3. 2.2.3. 2.2.3 简单测试
  3. 3. 3. 接入 Knife4j 作为 Swagger UI 界面
    1. 3.1. 3.1 修改依赖
    2. 3.2. 3.2 创建 SwaggerConfiguration
    3. 3.3. 3.3 简单测试
    4. 3.4. 3.4 再看 SwaggerConfiguration
    5. 3.5. 3.5 其它解决方案
  4. 4. 4. 接入 YApi 统一管理
  5. 5. 666. 彩蛋