03.01 接口api 之Swagger

今天我們來說說什麼是Swagger?

就是把相關的信息存儲在它定義的描述文件裡面(yml或json格式),再通過維護這個描述文件可以去更新接口文檔,以及生成各端代碼。而Springfox-swagger,則可以通過掃描代碼去生成這個描述文件。

好處:

1、是一款讓你更好的書寫API文檔的規範且完整框架。
2、提供描述、生產、消費和可視化RESTful Web Service。
3、是由龐大工具集合支撐的形式化規範。這個集合涵蓋了從終端用戶接口、底層代碼庫到商業API管理的方方面面。

4,這個框架可以自動為你的業務代碼生成restfut風格的api,而且還提供相應的測試界面,自動顯示json格式的響應。大大方便了後臺開發人員與前端的溝通與聯調成本

缺點:

如果使用的接口參數和返回值相對比較簡單,即如果都是處理成單表操作的接口,那麼使用swagger是明智選擇,但是如果接口參數本身很複雜,接口的返回值同樣非常複雜,那麼swagger的作用就會縮小.因此複雜業務的接口文檔或者wiki編寫是必需的,簡單的接口或者單表操作使用swagger。

swagger進行API管理

目前 springfox 是一個很好的選擇,它內部會自動解析Spring容器中Controller暴露出的接口,並且也提供了一個界面用於展示或調用這些API。下圖就是簡單的一個使用springfox的API展示界面。


springfox的前身是swagger-springmvc,用於springmvc與swagger的整合。

如若在springboot項目中使用springfox,需要3個步驟:

1、maven添加springfox依賴

2、啟動類加上@EnableSwagger2註解

3、構造Docket bean用於展示API

配置完之後進入 http://{path}:{port}/swagger-ui.html 即可查看controller中的接口信息,並按照Docket中配置的規則進行展示。

springfox實現原理

在分析springfox實現原理之前,首先看下springfox對文檔Documentation的定義:


接口api 之Swagger

文檔Documentation定義得很清晰,主要由groupName(分組名)、basePath(contextPath)、apiListings(API列表集)、resourceListing(資源列表集)等屬性組成。

其中API列表被封裝成ApiListing。ApiListing中又持有ApiDesciption集合引用,每個ApiDesciption都持有一個API集合的引用,Operation也就是具體的接口操作,內部包含了該接口對應的http方法、produces、consumes、協議、參數集、響應消息集等諸多元素。

springfox通過spring-plugin的方式將Plugin註冊到Spring上下文中,然後使用這些plugin進行API的掃描工作,這裡的掃描工作其實也就是構造Documentation的工作,把掃描出的結果封裝成Documentation並放入到DocumentationCache內存緩存中,之後swagger-ui界面展示的API信息通過Swagger2Controller暴露,Swagger2Controller內部直接從DocumentationCache中尋找Documentation。

下圖就是部分Plugin具體構造對應的文檔信息:


接口api 之Swagger

代碼細節方面的分析:

很明顯,入口處在@EnableSwagger2註解上,該註解會import一個配置類Swagger2DocumentationConfiguration。

Swagger2DocumentationConfiguration做的事情:

1、構造Bean。比如HandlerMapping,HandlerMapping是springmvc中用於處理請求與handler(controller中的方法)之間映射關係的接口,springboot中默認使用的HandlerMapping是RequestMappingHandlerMapping,Swagger2DocumentationConfiguration配置類裡構造的是PropertySourcedRequestMappingHandlerMapping,該類繼承RequestMappingHandlerMapping。

2、import其它配置類,比如SpringfoxWebMvcConfiguration、SwaggerCommonConfiguration

3、掃描指定包下的類,並註冊到Spring上下文中

SpringfoxWebMvcConfiguration配置類做的事情跟Swagger2DocumentationConfiguration類似,不過多了一步構造PluginRegistry過程。該過程使用@EnablePluginRegistries註解實現:

接口api 之Swagger

@EnablePluginRegistries註解是spring-plugin模塊提供的一個基於Plugin類型註冊PluginRegistry實例到Spring上下文的註解。

@EnablePluginRegistries註解內部使用PluginRegistriesBeanDefinitionRegistrar註冊器去獲取註解的value屬性(類型為Plugin接口的Class數組);然後遍歷這個Plugin數組,針對每個Plugin在Spring上下文中註冊PluginRegistryFactoryBean,並設置相應的name和屬性。

如果處理的Plugin有@Qualifier註解,那麼這個要註冊的PluginRegistryFactoryBean的name就是@Qualifier註解的value,否則name就是插件名首字母小寫+Registry的格式(比如DocumentationPlugin對應構造的bean的name就是documentationPluginRegistry)。

PluginRegistriesBeanDefinitionRegistrar註冊器處理過程:

接口api 之Swagger

PluginRegistryFactoryBean是一個FactoryBean,其內部真正構造的bean的類型是OrderAwarePluginRegistry。OrderAwarePluginRegistry實例化過程中會調用create靜態方法,傳入的plugin集合使用aop代理生成一個ArrayList,這個list中的元素就是Spring上下文中所有的類型為之前遍歷的Plugin的bean。

PluginRegistryFactoryBean的getObject方法:

接口api 之Swagger

接口api 之Swagger

這裡的targetSource是在PluginRegistryFactoryBean的父類AbstractTypeAwareSupport(實現了InitializingBean接口)中的afterPropertiesSet方法中初始化的(type屬性在PluginRegistriesBeanDefinitionRegistrar註冊器中已經設置為遍歷的Plugin):

接口api 之Swagger

BeansOfTypeTargetSource的getTarget方法:

接口api 之Swagger

舉個例子:比如SpringfoxWebMvcConfiguration中的@EnablePluginRegistries註解裡的DocumentationPlugin這個Plugin,在處理過程中會找出Spring上下文中所有的Docket(Docket實現了DocumentationPlugin接口),並把該集合設置成name為documentationPluginRegistry、類型為OrderAwarePluginRegistry的bean,註冊到Spring上下文中。

DocumentationPluginsManager類會在之前提到過的配置類中被掃描出來,它內部的各個pluginRegistry屬性都是@EnablePluginRegistries註解內部構造的各種pluginRegistry實例:

接口api 之Swagger

DocumentationPluginsBootstrapper啟動類也會在之前提供的配置類中被掃描出來。它實現了SmartLifecycle接口,在start方法中,會獲取之前初始化的所有documentationPlugins(也就是Spring上下文中的所有Docket)。遍歷這些Docket並進行scan掃描(使用RequestMappingHandlerMapping的getHandlerMethods方法獲取url與方法的所有映射關係,然後進行一系列API解析操作),掃描出來的結果封裝成Documentation並添加到DocumentationCache中:

接口api 之Swagger

以上就是API解析、掃描的大致處理過程,整理如下:


接口api 之Swagger


下面分析一下HandlerMapping的處理過程。

PropertySourcedRequestMappingHandlerMapping在Swagger2DocumentationConfiguration配置類中被構造:

接口api 之Swagger

PropertySourcedRequestMappingHandlerMapping初始化過程中會設置優先級為Ordered.HIGHEST_PRECEDENCE + 1000,同時還會根據Swagger2Controller得到RequestMappingInfo映射信息,並設置到handlerMethods屬性中。

PropertySourcedRequestMappingHandlerMapping複寫了lookupHandlerMethod方法,首先會去handlerMethods屬性中查詢是否存在對應的映射關係,沒找到的話使用下一個HandlerMapping進行處理:

接口api 之Swagger

Swagger2Controller中只有一個mapping方法,默認的path值為/v2/api-docs,可以通過配置 springfox.documentation.swagger.v2.path 進行修改。所以默認情況下 /v2/api-docs?group=person-api、/v2/api-docs?group=user-api 這些地址都會被Swagger2Controller所處理。

Swagger2Controller內部獲取文檔信息會去DocumentationCache中查找:

接口api 之Swagger

引入springfox帶來的影響

影響主要有2點:

應用啟動速度變慢,因為額外加載了springfox中的信息,同時內存中也緩存了這些API信息

多了一個HandlerMapping,並且優先級高。以下是springboot應用DispatcherServlet的HandlerMapping集合。其中springfox構造的PropertySourcedRequestMappingHandlerMapping優先級最高。優先級最高說明第一次查詢映射關係都是走PropertySourcedRequestMappingHandlerMapping,而程序中大部分請求都是在RequestMappingHandlerMapping中處理的

接口api 之Swagger

優先級問題可以使用BeanPostProcessor處理,修改優先級:

接口api 之Swagger


SpringBoot項目配置 swagger

<code>@EnableSwagger2@Configurationpublic class Swagger2Config {    @Bean    public Docket createRestApi() {        return new Docket(DocumentationType.SWAGGER_2)                .apiInfo(apiInfo())                .select()                //為當前包路徑                .apis(RequestHandlerSelectors.any())                .paths(PathSelectors.any())                .build();    }    //構建 api文檔的詳細信息函數    private ApiInfo apiInfo() {        return new ApiInfoBuilder()                //頁面標題                .title("功能測試")                //創建人                .contact(new Contact("Edison", "[email protected]", "[email protected]"))                //版本號                .version("1.0")                //描述                .description("API 描述")                .build();    }/<code>


maven.xml

<code><dependency>    <groupid>io.springfox/<groupid>    <artifactid>springfox-swagger2/<artifactid>    <version>2.6.1/<version>/<dependency><dependency>    <groupid>io.springfox/<groupid>    <artifactid>springfox-swagger-ui/<artifactid>    <version>2.6.1/<version>/<dependency>/<code>

這是ui把所有暴露成api。是不是非常簡單。喜歡記得點贊轉發。


接口api 之Swagger


分享到:


相關文章: