場景
在項目開發中我們對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();
}
}
這種方式測試單個接口很方便,但有個不足是每次測試單個接口,基本上相當於重啟了項目,當項目很大時運行可能比較耗時。
注:可通過執行整個測試類、或在structure里選中多個方法批量跑單元測試;或者在/src/test/resources/下單獨定義測試需要的配置,這樣能加快啟動時間。
於是想能否項目只啟動一次,然后調各個接口測試。
一個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