文章目录

  • 简介
  • 一、Swagger简单使用
  • 二、Swagger原理
  • 三、Swagger架构分析及组成
  • 其他

简介

API的全称是应用编程接口(Application Programming Interface)
在互联网时代,把网站的服务封装成一系列计算机易识别的数据接口开放出去,供第三方开发者使用,这种行为就叫做开放网站的API,与之对应的,所开放的API就被称作Open API。

swagger 是一个 api 文档维护组织,后来成为了 Open API 标准的主要定义者

**优点

  • RestFul API文档在线生成工具—>>>API文档与API同步更新
  • 可以直接运行,可以在线测试API接口
  • 支持多种语言:(Java,php…)

一、Swagger简单使用

Pom文件配置:

Swagger2需要导入两个资源依赖:

#Swagger2资源依赖
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version>
</dependency>

Swagger3只需要导入一个资源依赖:

# Swagger3资源依赖
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-boot-starter -->
<dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version>
</dependency>

Swagger Config配置

package cn.netxiaobao.demo;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;@EnableOpenApi //开启Swagger3
@Configuration
public class Swagger3 {@Beanpublic Docket docket() {return new Docket(DocumentationType.OAS_30) // v2 不同.select().apis(RequestHandlerSelectors.basePackage("cn.netXiaobao.demo"))//设置扫描路径.build();}
}

到此,Swagger配置完毕,启动程序即可

二、Swagger原理

springfox的大致原理就是,在项目启动的过种中,spring上下文在初始化的过程,框架自动跟据配置加载一些swagger相关的bean到当前的上下文中,并自动扫描系统中可能需要生成api文档那些类,并生成相应的信息缓存起来。如果项目MVC控制层用的是springMvc那么会自动扫描所有Controller类,跟据这些Controller类中的方法生成相应的api文档。

如果只用springfox的默认的配置的话,与springmvc集成起来非常简单,只要写一个类似于以下代码的类放到你的项目里就行了,代码如下

@Configuration
@EnableWebMvc
@EnableSwagger2
publicclass ApiConfig {}

注意到,上面是一个空的java类文件,类名可以随意指定,但必须加入上述类中标出的@Configuration、@EnableWebMvc、@EnableSwagger2三个注解,这样就完成了springmvc与springfox的基本集成,有了三个注解,项目启动后就可以直接用类似于以下的地址来查看api列表了:

http://127.0.0.1:8080/jadDemo/swagger-ui.html

这确实是一个很神奇的效果,简单的三个注解,系统就自动显示出项目里所有Controller类的所有api了。现在,我们就这个配置类入手,简单分析它的原理。这个类中没有任何代码,很显然,三个注解起了至关重要的作用。其中@Configuration注解是spring框架中本身就有的,它是一个被@Component元注解标识的注解,所以有了这个注解后,spring会自动把这个类实例化成一个bean注册到spring上下文中。第二个注解@EnableWebMvc故名思义,就是启用springmvc了,在Eclipse中点到这个注解里面简单看一下,它就是通过元注解@Import(DelegatingWebMvcConfiguration.class)往spring context中塞入了一个DelegatingWebMvcConfiguration类型的bean。我想,这个类的目的应该就是为swagger提供了一些springmvc方面的配置吧。第三个注解:@EnableSwagger2,看名字应该可以想到,是用来集成swagger2的,他通过元注解:@Import({Swagger2DocumentationConfiguration.class}),又引入了一个Swagger2DocumentationConfiguration类型的配置bean,而这个就是Swagger的核心配置了。它里面的代码如下:

@Configuration
@Import({ SpringfoxWebMvcConfiguration.class, SwaggerCommonConfiguration.class })
@ComponentScan(basePackages = {"springfox.documentation.swagger2.readers.parameter","springfox.documentation.swagger2.web","springfox.documentation.swagger2.mappers"})publicclassSwagger2DocumentationConfiguration {@Beanpublic JacksonModuleRegistrar swagger2Module() {returnnewSwagger2JacksonModule();}
}

这个类头部通过一些注解,再引入SpringfoxWebMvcConfiguration类和SwaggerCommonConfiguration类,并通过ComponentScan注解,自动扫描springfox .swagger2相关的的bean到spring context中。这里,我最感兴趣的是SpringfoxWebMvcConfiguration这个类,这个类我猜应该就是springfox集成mvc比较核心的配置了,点进去,看到以下代`码:

@Configuration
@Import({ModelsConfiguration.class })
@ComponentScan(basePackages = {"springfox.documentation.spring.web.scanners","springfox.documentation.spring.web.readers.operation","springfox.documentation.spring.web.plugins","springfox.documentation.spring.web.paths"
})@EnablePluginRegistries({ DocumentationPlugin.class,ApiListingBuilderPlugin.class,OperationBuilderPlugin.class,ParameterBuilderPlugin.class,ExpandedParameterBuilderPlugin.class,ResourceGroupingStrategy.class,OperationModelsProviderPlugin.class,DefaultsProviderPlugin.class,PathDecorator.class
})publicclassSpringfoxWebMvcConfiguration {}

这个类中下面的代码,无非就是通过@Bean注解再加入一些新的Bean,我对它的兴趣不是很大,我最感兴趣的是头部通过@EnablePluginRegistries加入的那些东西。springfox是基于spring-plug的机制整合swagger的,spring-plug具体是怎么实现的,我暂时还没有时间去研究spring-plug的原理。但在下文会提到自己写一个plug插件来扩展swagger的功能。上面通过@EnablePluginRegistries加入的plug中,还没有时间去看它全部的代码,目前我看过的代码主要有ApiListingBuilderPlugin.class,OperationBuilderPlugin.class,ParameterBuilderPlugin.class, ExpandedParameterBuilderPlugin.class,

我们把注意点放到上文SpringfoxWebMvcConfiguration这个类代码头部的ComponentScan注解内容上来,这一段注解中扫描了一个叫springfox.documentation.spring.web.plugins的package,这个package在springfox-spring-web-2.6.1.jar中可以找到。这个package下,我们发现有两个非常核心的类,那就是DocumentationPluginsManager和DocumentationPluginsBootstrapper。对于第一个DocumentationPluginsManager,它是一个没有实现任何接口的bean,但它内部有诸多PluginRegistry类型的属性,而且都是通过@Autowired注解把属性值注入进来的。接合它的类名来看,很容易想到,这个就是管理所有plug的一个管理器了。很好理解,因为ComponentScan注解的配置,所有的plug实例都会被spring实例化成一个bean,然后被注入到这个DocumentationPluginsManager实例中被统一管理起来。在这个package中的另一个重要的类DocumentationPluginsBootstrapper,看名字就可以猜到,他可能就是plug的启动类了。点进去看具体时就可以发现,他果然是一个被@Component标识了的组件,而且它的构造方法中注入了刚刚描述的DocumentationPluginsManager实例,而且最关键的,它还实现了SmartLifecycle接口。对spring bean生命周期有所了解的人的都知道,这个组件在被实例化为一个bean纳入srping context中被管理起来的时候,会自动调用它的start()方法。点到start()中看代码时就会发现,它有一行代码scanDocumentation(buildContext(each));就是用来扫描api文档的。进一步跟踪这个方法的代码,就可以发现,这个方法最终会通过它的DocumentationPluginsManager属性把所有plug调起一起扫描整个系统并生成api文档。扫描的结果,缓存在DocumentationCache这个类的一个map属性中。

以上就是,srpingMvc整合springfox的大致原理。它主要是通过EnableSwagger2注解,向spring context注入了一系列bean,并在系统启动的时候自动扫描系统的Controller类,生成相应的api信息并缓存起来。此外,它还注入了一些被@Controller注解标识的Controller类,作为ui模块访问api列表的入口。比如springfox-swagger2-2.6.1.jar包中的Swagger2Controller类。这个Controller就是ui模块中用来访问api列表的界面地址。在访问http://127.0.0.1:8080/jadDemo/swagger-ui.html这个地址查看api列表时,通过浏览器抓包就可以看到,它是通过类似于http://127.0.0.1:8080/jadDemo/v2/api-docs?group=sysGroup这样的地址异步获得api信息(Json格式)并显示到界面上,这个地址后台对应的Controller入口就是上文的Swagger2Controller类,这个类收到请求后,直接从事先初始化好的缓存中的取出api信息生成json字符串返回。

springfox.documentation.swagger.web.ApiResourceController 定义了/swagger-resource相关的API接口来返回我们定义的配置类SwaggerResourcesProvider
Controller定义如下:

package springfox.documentation.swagger.web;
@RestController
@ApiIgnore
@RequestMapping({"${springfox.documentation.swagger-ui.base-url:}/swagger-resources"})
public class ApiResourceController {@Autowired(required = false)private SecurityConfiguration securityConfiguration;@Autowired(required = false)private UiConfiguration uiConfiguration;private final SwaggerResourcesProvider swaggerResources;@Autowiredpublic ApiResourceController(SwaggerResourcesProvider swaggerResources,@Value("${springfox.documentation.swagger-ui.base-url:}") String swaggerUiBaseUrl) {this.swaggerResources = swaggerResources;this.uiConfiguration = UiConfigurationBuilder.builder().copyOf(uiConfiguration).swaggerUiBaseUrl(StringUtils.trimTrailingCharacter(swaggerUiBaseUrl, '/')).build();this.securityConfiguration = SecurityConfigurationBuilder.builder().copyOf(securityConfiguration).build();}@GetMapping(value = "/configuration/security", produces = MediaType.APPLICATION_JSON_VALUE)public ResponseEntity<SecurityConfiguration> securityConfiguration() {return new ResponseEntity<>(securityConfiguration, HttpStatus.OK);}@GetMapping(value = "/configuration/ui", produces = MediaType.APPLICATION_JSON_VALUE)public ResponseEntity<UiConfiguration> uiConfiguration() {return new ResponseEntity<>(uiConfiguration, HttpStatus.OK);}@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)public ResponseEntity<List<SwaggerResource>> swaggerResources() {return new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK);}
}

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中查找:

@RequestMapping(value = DEFAULT_URL,method = RequestMethod.GET,produces = { APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE })
@PropertySourcedMapping(value = "${springfox.documentation.swagger.v2.path}",propertyKey = "springfox.documentation.swagger.v2.path")
@ResponseBody
public ResponseEntity<Json> getDocumentation(@RequestParam(value = "group", required = false) String swaggerGroup,HttpServletRequest servletRequest) {String groupName = Optional.fromNullable(swaggerGroup).or(Docket.DEFAULT_GROUP_NAME);Documentation documentation = documentationCache.documentationByGroup(groupName);if (documentation == null) {return new ResponseEntity<Json>(HttpStatus.NOT_FOUND);}Swagger swagger = mapper.mapDocumentation(documentation);UriComponents uriComponents = componentsFrom(servletRequest, swagger.getBasePath());swagger.basePath(Strings.isNullOrEmpty(uriComponents.getPath()) ? "/" : uriComponents.getPath());if (isNullOrEmpty(swagger.getHost())) {swagger.host(hostName(uriComponents));}return new ResponseEntity<Json>(jsonSerializer.toJson(swagger), HttpStatus.OK);
}

以上就是API解析、扫描的大致处理过程,整理如下:

三、Swagger架构分析及组成

springfox对文档Documentation的定义

文档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具体构造对应的文档信息:

代码细节方面的分析:

很明显,入口处在@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注解实现:

@EnablePluginRegistries({ DocumentationPlugin.class,ApiListingBuilderPlugin.class,OperationBuilderPlugin.class,ParameterBuilderPlugin.class,ExpandedParameterBuilderPlugin.class,ResourceGroupingStrategy.class,OperationModelsProviderPlugin.class,DefaultsProviderPlugin.class,PathDecorator.class,ApiListingScannerPlugin.class
})

@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)。

其他

参考: https://blog.csdn.net/qq_25615395/article/details/70229139
https://developer.aliyun.com/article/599809
https://www.jianshu.com/p/9f7af2262b96

Spring Boot: SpringFox Swagger原理解析及简单实用相关推荐

  1. Spring Boot(18)---启动原理解析

    Spring Boot(18)---启动原理解析 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会 ...

  2. Spring Boot自动装配过程解析及简单Demo演示

    文章目录 1.约定大于配置 2.自动装配原理 2.1.`@SpringBootApplication` 2.2.`@EnableAutoConfiguration` 2.3.`@Import` 2.4 ...

  3. Spring Boot集成Swagger导入YApi@无界编程

    接口APi开发现状 现在开发接口都要在类似YApi上写文档,这样方便不同的团队之间协作,同步更新接口,提高效率. 但是如果接口很多,你一个个手工在YApi去录入无疑效率很低. 如果是使用Spring ...

  4. Spring Boot 集成 Swagger 生成 RESTful API 文档

    原文链接: Spring Boot 集成 Swagger 生成 RESTful API 文档 简介 Swagger 官网是这么描述它的:The Best APIs are Built with Swa ...

  5. Spring Boot 整合 Swagger

    一.为什么要用 Swagger 现在的开发模式,一般都是前后端分离的,开发接口文档就显得尤为重要,前端人员需要按照后端的功能文档调用对应的接口.在没有使用 API 文档之前,很多公司都是在纸或者 Ma ...

  6. Spring Boot自动配置原理、实战

    Spring Boot自动配置原理 Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射. org.s ...

  7. 芋道 Spring Boot 自动配置原理

    转载自  芋道 Spring Boot 自动配置原理 1. 概述 友情提示:因为本文是分享 Spring Boot 自动配置的原理,所以需要胖友有使用过 Spring Boot 的经验.如果还没使用过 ...

  8. Spring Boot和Swagger UI

    我已经一年没有从头开始开发Spring Web应用程序了,如果我不参加QA自动化工程师的培训,那么这段时间甚至会更长. 由于这个原因,我开发了一个示例REST应用程序. 除了Swagger,一切对我来 ...

  9. Spring Boot集成Swagger

    Spring Boot集成Swagger @(Swagger)[swagger, springfox, springboot] Spring Boot集成Swagger 前言 基本概述 案例 引入依赖 ...

最新文章

  1. spring-amqp生产者手动ACK
  2. 加 解密的c语言程序,c语言程序设计文个件加密解密.doc
  3. 【哲学】形而上学具体指什么?metaphysics
  4. [深入JUnit] 测试运行的入口
  5. 该虚拟机似乎正在使用
  6. js和jquery书籍
  7. 诗与远方:无题(八十二)- 遇到你真好
  8. Flash写操作流程
  9. java项目打jar包,并且在cmd命令行运行
  10. 不容错过!Greenplum的又一本好书
  11. 永洪bi_永洪BI_咨询服务_数据服务_云市场-华为云
  12. 【彩虹代刷v5.8】去除后门增加多套模板修复多处BUG[全开源免授权]
  13. Mac中彻底删除搜狗拼音输入法一法
  14. 六级听力技巧与备考策略
  15. python闰月计算_Python日期计算,编程练习题实例四
  16. Python爬虫:老兵不死,用数据纪念2019男篮世界杯
  17. SPI DMA 通信配置
  18. 用python代码实现 函数调用 烤红薯的例子
  19. 对抗拖延症最直接有效的方法
  20. 学习PMP,你最看重培训机构哪些点?

热门文章

  1. JAVA基础11 网络编程
  2. Go社区主流Kakfa客户端简要对比
  3. [FireDAC][Phys][SQLite]-326. Cannot perform the action, because the previous action is in progress.
  4. 学python电脑硬件_Micropython 玩转硬件系列1:环境搭建
  5. 「真®全栈之路」Web前端开发的后端指南
  6. list的倒数第二位元素移动到第一位
  7. iNFTnews | 元宇宙如何为性别酷儿人群提供包容空间
  8. Chrome任务栏图标变白色的解决方法
  9. 什么是跨域问题,跨域问题如何解决
  10. 收纳箱底部滚轮怎样装_抽屉式收纳箱怎么样 收纳其实很简单