Springfox swagger2 源码解析
doc访问页面 http://localhost:8080/doc.html
api-json访问页面 http://localhost:8080/v2/api-docs
pom依赖
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-boot-starter --><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.2</version></dependency>
根据路径/v2/api-docs顺藤摸瓜 找到 Swagger2ControllerWebMvc
@RequestMapping(method = RequestMethod.GET,produces = {APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE})public ResponseEntity<Json> 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<HttpServletRequest> context= new SwaggerTransformationContext<>(swagger, servletRequest);List<WebMvcSwaggerTransformationFilter> 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 DocumentationPluginsBootstrapperextends AbstractDocumentationPluginsBootstrapperimplements SmartLifecycle{public DocumentationPluginsBootstrapper(DocumentationPluginsManager documentationPluginsManager,List<RequestHandlerProvider> 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。
@Componentpublic class DocumentationPluginsManager {@Autowired@Qualifier("documentationPluginRegistry")private PluginRegistry<DocumentationPlugin, DocumentationType> documentationPlugins;@Autowired@Qualifier("apiListingBuilderPluginRegistry")private PluginRegistry<ApiListingBuilderPlugin, DocumentationType> apiListingPlugins;@Autowired@Qualifier("parameterBuilderPluginRegistry")private PluginRegistry<ParameterBuilderPlugin, DocumentationType> parameterPlugins;@Autowired@Qualifier("expandedParameterBuilderPluginRegistry")private PluginRegistry<ExpandedParameterBuilderPlugin, DocumentationType> parameterExpanderPlugins;@Autowired@Qualifier("operationBuilderPluginRegistry")private PluginRegistry<OperationBuilderPlugin, DocumentationType> operationBuilderPlugins;@Autowired@Qualifier("operationModelsProviderPluginRegistry")private PluginRegistry<OperationModelsProviderPlugin, DocumentationType> operationModelsProviders;@Autowired@Qualifier("defaultsProviderPluginRegistry")private PluginRegistry<DefaultsProviderPlugin, DocumentationType> defaultsProviders;@Autowired@Qualifier("pathDecoratorRegistry")private PluginRegistry<PathDecorator, DocumentationContext> pathDecorators;@Autowired@Qualifier("apiListingScannerPluginRegistry")private PluginRegistry<ApiListingScannerPlugin, DocumentationType> apiListingScanners;@Autowired@Qualifier("responseBuilderPluginRegistry")private PluginRegistry<ResponseBuilderPlugin, DocumentationType> responsePlugins;@Autowired@Qualifier("modelNamesRegistryFactoryPluginRegistry")private PluginRegistry<ModelNamesRegistryFactoryPlugin, DocumentationType> modelNameRegistryFactoryPlugins;public Collection<DocumentationPlugin> documentationPlugins() throws IllegalStateException {List<DocumentationPlugin> plugins = documentationPlugins.getPlugins();ensureNoDuplicateGroups(plugins);if (plugins.isEmpty()) {return singleton(defaultDocumentationPlugin());}return plugins;}
例如 OperationBuilderPlugin
PluginRegistry<OperationBuilderPlugin,DocumentationType> operationBuilderPlugins
Control + H 查看其继承结构

栗子:
SwaggerResponseMessageReader实现了ResponseMessage的读取。read()方法从OperationContext上下文中获取ApiOperation、ResponseHeader、ApiResponse注解信息。
public class SwaggerResponseMessageReader implements OperationBuilderPlugin {protected Compatibility<Set<ResponseMessage>, Set<Response>> read(OperationContext context) {}}
PluginRegistry
Spring Plugin提供一个标准的Plugin<S>接口供开发人员继承使用声明自己的插件机制,然后通过@EnablePluginRegistries注解依赖注入到Spring的容器中,Spring容器会为我们自动匹配到插件的所有实现子对象,最终我们在代码中使用时,通过依赖注入注解,注入PluginRegistry<T extends Plugin<S>, S>对象拿到插件实例进行操作。
项目中自定义swagger2Config配置文件,注入Docket对象,即一个DocumentationPlugin插件。
public class Docket implements DocumentationPlugin@Configurationpublic class Swagger2Config {@Beanpublic Docket createRestApi() {List<Response> globalResponses = new ArrayList<>();// 根据Enum构建了全局的Responsefor (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 {@Beanpublic Defaults defaults() {return new Defaults();}@Beanpublic DocumentationCache resourceGroupCache() {return new DocumentationCache();}@Beanpublic JsonSerializer jsonSerializer(List<JacksonModuleRegistrar> moduleRegistrars) {return new JsonSerializer(moduleRegistrars);}@Beanpublic DescriptionResolver descriptionResolver(Environment environment) {return new DescriptionResolver(environment);}@Beanpublic HandlerMethodResolver methodResolver(TypeResolver resolver) {return new HandlerMethodResolver(resolver);}@Beanpublic PathProvider pathProvider() {return new DefaultPathProvider();}}
其他文章:Swagger2 Response统一默认返回信息
喜欢就关注下吧

6171

被折叠的 条评论
为什么被折叠?



