Springfox swagger2 源码解析

网友投稿 918 2022-05-29

Springfox swagger2 源码解析

doc访问页面 http://localhost:8080/doc.html

api-json访问页面 http://localhost:8080/v2/api-docs

pom依赖

com.github.xiaoymin knife4j-spring-boot-starter 3.0.2

找starter的启动配置文件spring.factories文件找到启动类,做了一些bean的配置。

# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.github.xiaoymin.knife4j.spring.configuration.Knife4jAutoConfiguration

根据路径/v2/api-docs顺藤摸瓜 找到 Swagger2ControllerWebMvc

@RequestMapping( method = RequestMethod.GET, produces = {APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE}) public ResponseEntity getDocumentation( @RequestParam(value = "group", required = false) String swaggerGroup, HttpServletRequest servletRequest) { String groupName = ofNullable(swaggerGroup).orElse(Docket.DEFAULT_GROUP_NAME); Documentation documentation = documentationCache.documentationByGroup(groupName); if (documentation == null) { LOGGER.warn("Unable to find specification for group {}", groupName); return new ResponseEntity<>(HttpStatus.NOT_FOUND); } Swagger swagger = mapper.mapDocumentation(documentation); SwaggerTransformationContext context = new SwaggerTransformationContext<>(swagger, servletRequest); List filters = transformations.getPluginsFor(DocumentationType.SWAGGER_2); for (WebMvcSwaggerTransformationFilter each : filters) { context = context.next(each.transform(context)); } return new ResponseEntity<>(jsonSerializer.toJson(context.getSpecification()), HttpStatus.OK); } }

从缓存中获取文档

Documentation documentation = documentationCache.documentationByGroup(groupName);

何时加载缓存文档呢?

由文档加载器DocumentationPluginsbootstrapper进行加载,类实现了SmartLifecycle接口,当spring加载完bean后,调用start()方法进行加载。

public class DocumentationPluginsBootstrapper extends AbstractDocumentationPluginsBootstrapper implements SmartLifecycle{ public DocumentationPluginsBootstrapper( DocumentationPluginsManager documentationPluginsManager, List handlerProviders, DocumentationCache scanned, ApiDocumentationScanner resourceListing, TypeResolver typeResolver, Defaults defaults, PathProvider pathProvider, Environment environment) { super( documentationPluginsManager, handlerProviders, scanned, resourceListing, defaults, typeResolver, pathProvider); this.environment = environment; } // bean 加载完成后调用 public void start() { if (initialized.compareAndSet(false, true)) { LOGGER.debug("Documentation plugins bootstrapped"); super.bootstrapDocumentationPlugins(); } } }

Spring SmartLifecycle 在容器所有bean加载和初始化完毕执行

在使用Spring开发时,我们都知道,所有bean都交给Spring容器来统一管理,其中包括每一个bean的加载和初始化。

有时候我们需要在Spring加载和初始化所有bean后,接着执行一些任务或者启动需要的异步服务,这样我们可以使用 SmartLifecycle 来做到。

这个和 @PostConstruct、@PreDestroy 的bean的初始化和销毁方法不同,Bean生命周期级别和容器生命周期级别在应用场景上是有区别的。

SmartLifecycle 是一个接口。当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法)。

文档插件管理器 DocumentationPluginsManager

此类以PluginRegistry的方式注入了一系列插件

documentationPlugins()方法调用了DocumentationPlugin 文档插件,若没有则生成一个默认的插件Docket,通常在Swagger2Configuration配置文件会注入一个Docket。

@Component public class DocumentationPluginsManager { @Autowired @Qualifier("documentationPluginRegistry") private PluginRegistry documentationPlugins; @Autowired @Qualifier("apiListingBuilderPluginRegistry") private PluginRegistry apiListingPlugins; @Autowired @Qualifier("parameterBuilderPluginRegistry") private PluginRegistry parameterPlugins; @Autowired @Qualifier("expandedParameterBuilderPluginRegistry") private PluginRegistry parameterExpanderPlugins; @Autowired @Qualifier("operationBuilderPluginRegistry") private PluginRegistry operationBuilderPlugins; @Autowired @Qualifier("operationModelsProviderPluginRegistry") private PluginRegistry operationModelsProviders; @Autowired @Qualifier("defaultsProviderPluginRegistry") private PluginRegistry defaultsProviders; @Autowired @Qualifier("pathDecoratorRegistry") private PluginRegistry pathDecorators; @Autowired @Qualifier("apiListingScannerPluginRegistry") private PluginRegistry apiListingScanners; @Autowired @Qualifier("responseBuilderPluginRegistry") private PluginRegistry responsePlugins; @Autowired @Qualifier("modelNamesRegistryFactoryPluginRegistry") private PluginRegistry modelNameRegistryFactoryPlugins; public Collection documentationPlugins() throws IllegalStateException { List plugins = documentationPlugins.getPlugins(); ensureNoDuplicateGroups(plugins); if (plugins.isEmpty()) { return singleton(defaultDocumentationPlugin()); } return plugins; }

例如 OperationBuilderPlugin

PluginRegistry operationBuilderPlugins

Control + H 查看其继承结构

栗子:

SwaggerResponseMessageReader实现了ResponseMessage的读取。read()方法从OperationContext上下文中获取ApiOperation、ResponseHeader、ApiResponse注解信息。

public class SwaggerResponseMessageReader implements OperationBuilderPlugin {

Springfox swagger2 源码解析

protected Compatibility, Set> read(OperationContext context) {}

}

PluginRegistry

Spring Plugin提供一个标准的Plugin接口供开发人员继承使用声明自己的插件机制,然后通过@EnablePluginRegistries注解依赖注入到Spring的容器中,Spring容器会为我们自动匹配到插件的所有实现子对象,最终我们在代码中使用时,通过依赖注入注解,注入PluginRegistry extends Plugin对象拿到插件实例进行操作。

项目中自定义swagger2Config配置文件,注入Docket对象,即一个DocumentationPlugin插件。

public class Docket implements DocumentationPlugin

@Configuration public class Swagger2Config { @Bean public Docket createRestApi() { List globalResponses = new ArrayList<>(); // 根据Enum构建了全局的Response for (ResponseCodeEnums item : ResponseCodeEnums.values()) { globalResponses.add(new ResponseBuilder() .code(String.valueOf(item.getCode())) .description(item.getDesc()) .build()); } return new Docket(DocumentationType.OAS_30) .useDefaultResponseMessages(true) .globalResponses(HttpMethod.GET, globalResponses) .globalResponses(HttpMethod.POST, globalResponses) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.dogs.doc.controller")) .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("Dogs APIs") .description("knife4j") .termsOfServiceUrl("") .version("3.0") .build(); }

springfox的配置文件SpringfoxWebConfiguration

EnablePluginRegistries启用插件

Defaults组件实现了一些默认的设置,如全局Response 200、401、403的返回信息。

@Configuration @Import({ ModelsConfiguration.class }) @ComponentScan(basePackages = { "springfox.documentation.spring.web.scanners", "springfox.documentation.spring.web.readers.operation", "springfox.documentation.spring.web.readers.parameter", "springfox.documentation.spring.web.plugins", "springfox.documentation.spring.web.paths" }) @EnablePluginRegistries({ DocumentationPlugin.class, ApiListingBuilderPlugin.class, OperationBuilderPlugin.class, ParameterBuilderPlugin.class, ResponseBuilderPlugin.class, ExpandedParameterBuilderPlugin.class, OperationModelsProviderPlugin.class, DefaultsProviderPlugin.class, PathDecorator.class, ApiListingScannerPlugin.class, ModelNamesRegistryFactoryPlugin.class }) public class SpringfoxWebConfiguration { @Bean public Defaults defaults() { return new Defaults(); } @Bean public DocumentationCache resourceGroupCache() { return new DocumentationCache(); } @Bean public JsonSerializer jsonSerializer(List moduleRegistrars) { return new JsonSerializer(moduleRegistrars); } @Bean public DescriptionResolver descriptionResolver(Environment environment) { return new DescriptionResolver(environment); } @Bean public HandlerMethodResolver methodResolver(TypeResolver resolver) { return new HandlerMethodResolver(resolver); } @Bean public PathProvider pathProvider() { return new DefaultPathProvider(); } }

总结:

swagger基于PluginRegistry的方式注册插件。 默认提供了配置类ApiInfo,用户可以自定义配置类,可配置的内容可以参考ApiInfo的属性。

Spring 容器

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【Unity3D日常开发】Unity3D中实现箭头指向目标点的效果
下一篇:MySQL用得好好的,为什么要转ES?
相关文章