场景
在项目开发中我们对dubbo接口通常可以通过junit编写单页测试来进行自测,配合spring-boot-starter-test
,通常是如下方式:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = XxxApplication.class)
public class XxxServiceTest {
@Autowired
private XxxService xxxService;
@Test
public void testFunc() throws Exception {
xxxService.func();
}
}
这种方式测试单个接口很方便,但有个不足是每次测试1个接口,基本上相当于重启了项目,当项目很大时执行比较耗时。
于是想能否项目只启动一次,然后调各个接口测试。
一个springboot项目启动好,当定义了controller时,我们可以通过浏览器或者postman这样的http工具调用接口,
那没有controller接口,只暴露了dubbo服务能否直接调用呢?
答案是肯定的,dubbo从很早的版本2.0.5开始就支持通过telnet命令来进行服务治理。
参考官方文档:http://dubbo.apache.org/zh/docs/v2.7/user/references/telnet/
比如项目的dubbo配置:
<dubbo:protocol name="dubbo" port="20001" threadpool="fixed" threads="200" />
dubbo端口是10001,通过telnet命令连接:telnet localhost 20001
连接后,常用命令:status -l
:查看服务状态,包括服务状态是否OK、核心线程数、在运行线程数等。
ls
:查看接口类列表。
ls -l com.cdfive.xxx.service.XxxService
:查看某接口类下所有接口方法。
invoke com.cdfive.xxx.service.XxxService.func({"name":"111","class":"xxx""}
:调用某接口方法。
invoke
命令让我们可以调用想测试的某个接口。
这种方式解决了的上面接口测试的问题,即项目启动1次,然后调想任意想测试的接口。
但它仍有不足是:操作步骤较繁琐,要先telnet连接,然后invoke调接口,而telnet窗口不像shell里有方便的自动完成功能,
并且接口方法和参数需要提前准备好。
如果有可视化的方式,当启动好项目能在界面上直接调dubbo接口就更方便了。
swagger和swagger-ui
官方:https://github.com/springfox/springfox/tree/master/springfox-swagger-ui
swagger是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。
在项目中使用swagger提供的@Api
、@ApiOperation
、@ApiModel
、@ApiModelProperty
等一系列注解标识在具体的接口和参数上,
然后通过swagger-ui提供的web界面,查看接口文档、测试接口调用。
集成步骤:
- 引入
swagger
、swagger-ui
依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
- 创建swagger配置类
/**
* @author cdfive
*/
@ConditionalOnProperty(name = "swagger.enable", matchIfMissing = false)
@EnableSwagger2
@Configuration
public class SwaggerConfig {
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.cdfive.xxx.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("xxx-service")
.description("xxx-service description")
.version("0.0.1")
.build();
}
}
注:swagger.enable
用于区分不同环境(如:开发、测试、生产),在生产环境需要禁用swagger。
- 在controller类的接口方法使用swagger注解
如:
@ApiOperation(value="修改用户密码", notes="根据用户id修改密码")
@ApiImplicitParams({
@ApiImplicitParam(paramType="query", name = "userId", value = "用户id", required = true, dataType = "Integer"),
@ApiImplicitParam(paramType="query", name = "password", value = "旧密码", required = true, dataType = "String"),
@ApiImplicitParam(paramType="query", name = "newPassword", value = "新密码", required = true, dataType = "String")
})
@RequestMapping("/modifyPassword")
public void modifyPassword(@RequestParam(value="userId") Integer userId
, @RequestParam(value="password") String password,
@RequestParam(value="newPassword") String newPassword) {
...
}
启动项目,访问http://ip:port/swagger-ui.html
查看swagger-ui的主页面。
swagger-dubbo
官方:https://github.com/Sayi/swagger-dubbo/
swagger-dubbo解析项目中的dubbo接口,基于swagger规范生成文档,然后我们可通过swagger-ui直接调用dubbo接口。
集成步骤:
- 引入
swagger-dubbo
依赖
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>swagger-dubbo</artifactId>
<version>2.0.1</version>
</dependency>
- 创建swagger-dubbo配置类
@ConditionalOnProperty(name = "swagger.dubbo.enable", matchIfMissing = false)
@EnableDubboSwagger
@Configuration
public class SwaggerDubboConfig {
...
}
注:swagger.dubbo。enable
用于区分不同环境(如:开发、测试、生产),在生产环境需要禁用swagger-dubbo。
启动项目,访问http://ip:port/swagger-dubbo/api-docs
查看swagger-dubbo解析生成的文档。
访问http://ip:port/swagger-ui.html
,发现顶部的下拉列表里只有1个选项:default(/v2/api-docs),
默认swagger-ui只展示了controller的接口,swagger-dubbo解析生成的文档打开是一个json串,并没有展示在swagger-ui上。
注:此时虽然swagger-ui页面没有展示,但可以通过http rest接口http://ip:port/h/com.xxx.XxService/xxxMethod
调用dubbo接口。
运行官方的dubbo-provider-springboot
示例,发现顶部的下拉列表变成了输入框,当启用跨越访问后就能看到解析除的dubbo接口。
在工程的/src/main/resources/static/distv2
的目录下,有定制的swagger-ui相关文件。
但如果每个项目中都加入这些前端相关的文件有点麻烦,希望在官方默认的swagger-ui页面中就能看到项目中的dubbo接口。
在springfox-swagger-ui
的官方介绍里有一句话:
Adds a JSON endpoint /swagger-resources which lists all of the swagger resources and versions configured for a given application.
在启动项目的日志里也能看到:Mapped "{[/swagger-resources/configuration/ui]}" onto public org.springframework.http.ResponseEntity<springfox.documentation.swagger.web.UiConfiguration> springfox.documentation.swagger.web.ApiResourceController.uiConfiguration()
Mapped "{[/swagger-resources/configuration/security]}" onto public org.springframework.http.ResponseEntity<springfox.documentation.swagger.web.SecurityConfiguration> springfox.documentation.swagger.web.ApiResourceController.securityConfiguration()
Mapped "{[/swagger-resources]}" onto public org.springframework.http.ResponseEntity<java.util.List<springfox.documentation.swagger.web.SwaggerResource>> springfox.documentation.swagger.web.ApiResourceController.swaggerResources()
springfox.documentation.swagger.web.ApiResourceController
暴露了3个地址,其中/swagger-resources
就是swagger-ui页面顶部下拉列表的数据源。
打开该controller的源码,发现是通过SwaggerResourcesProvider
接口实现的,该接口集成了guava的Supplier
接口。
查看接口只有1个实现类InMemorySwaggerResourcesProvider
,里面的get方法就是获取数据源。
swagger-dubbo解析的dubbo接口已生成了数据源,通过/swagger-dubbo/api-docs
暴露,因此对SwaggerDubboConfig
做一些改造:
/**
* @author cdfive
*/
@ConditionalOnProperty(name = "swagger.dubbo.enable", matchIfMissing = false)
@EnableDubboSwagger
@Configuration
public class SwaggerDubboConfig {
@Primary
@Bean
public SwaggerResourcesProvider swaggerResourcesProvider(Environment environment, DocumentationCache documentationCache) {
return new CustormSwaggerResourcesProvider(environment, documentationCache);
}
static class CustormSwaggerResourcesProvider extends InMemorySwaggerResourcesProvider {
public CustormSwaggerResourcesProvider(Environment environment, DocumentationCache documentationCache) {
super(environment, documentationCache);
}
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> swaggerResources = super.get();
SwaggerResource swaggerDubboResource = new SwaggerResource();
swaggerDubboResource.setName("dubbo");
swaggerDubboResource.setLocation("/swagger-dubbo/api-docs");
swaggerDubboResource.setSwaggerVersion("2.0");
swaggerResources.add(swaggerDubboResource);
return swaggerResources;
}
}
}
思路是自定义CustormSwaggerResourcesProvider
继承InMemorySwaggerResourcesProvider
,里面将dubbo对应的/swagger-dubbo/api-docs
数据源添加进去,通过@Primary
注解表示该实现类优先使用。
改造后重新启动项目,访问http://ip:port/swagger-ui.html
页面,顶部下拉列表就有了2个选项:
default(/v2/api-docs)和dubbo(/swagger-dubbo/api-docs),切换到dubbo后项目中的dubbo接口在界面展示了出来,并且输入参数值即可调用。
总结
- 项目可能经常需要在本地对dubbo接口进行自测,通常使用junit单元测试,结合spring-boot-test,如果项目很大启动测试可能很耗时。
- 先启动好项目,通过telnet连接dubbo服务,通过invoke命令能直接调用接口测试,但需要在命令里准备好接口和参数,不能可视化。
- 通过引入swagger-ui并结合swagger-dubbo能直接在界面调用dubbo接口,方便自测、测试和调试,能在一定程度上帮助提高开发效率。
参考
- Dubbo telnet文档 http://dubbo.apache.org/zh/docs/v2.7/user/references/telnet/
- springfox-swagger-ui https://github.com/springfox/springfox/tree/master/springfox-swagger-ui
- swagger-dubbo https://github.com/Sayi/swagger-dubbo/
- SpringBoot整合Swagger-UI https://blog.csdn.net/zhoubangbang1/article/details/111937946
- spring boot (2) 配置swagger2核心配置 docket https://www.cnblogs.com/guangzhou11/p/12186438.html
- 使用swagger作为restful api的doc文档生成 https://www.cnblogs.com/woshimrf/p/5863318.html
- 改造 Swagger UI 页面,实现集中查看多个项目的接口文档 https://testerhome.com/topics/9427
- Swagger 自定义UI界面 https://www.cnblogs.com/hanxue112253/p/10980804.html
- Springfox与swagger的整合使用与关系 https://www.cnblogs.com/water-1/p/10820235.html
- Dubbo微服务基于swagger自动生成文档及测试调用 https://www.jianshu.com/p/60c3418bf1b8
- 升级使用SpringFox的swagger-ui 3.0.0版本 https://blog.csdn.net/qq_15973399/article/details/107436089
- 尝鲜刚发布的 SpringFox 3.0.0,以前造的*可以不用了... https://didispace.blog.csdn.net/article/details/107424187