doc 访问页面 http://localhost:8080/doc.htmlapi-json 访问页面 http://localhost:8080/v2/api-docs
pom 依赖
<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>3.0.2</version></dependency>
复制代码
找 starter 的启动配置文件 spring.factories 文件找到启动类,做了一些 bean 的配置。
# Auto Configureorg.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<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 DocumentationPluginsBootstrapper extends AbstractDocumentationPluginsBootstrapper implements 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; }
复制代码
例如 OperationBuilderPluginPluginRegistry<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) {}}
PluginRegistrySpring Plugin 提供一个标准的 Plugin 接口供开发人员继承使用声明自己的插件机制,然后通过 @EnablePluginRegistries 注解依赖注入到 Spring 的容器中,Spring 容器会为我们自动匹配到插件的所有实现子对象,最终我们在代码中使用时,通过依赖注入注解,注入 PluginRegistry extends Plugin 对象拿到插件实例进行操作。
项目中自定义 swagger2Config 配置文件,注入 Docket 对象,即一个 DocumentationPlugin 插件。public class Docket implements DocumentationPlugin
@Configurationpublic class Swagger2Config {
@Bean public Docket createRestApi() {
List<Response> 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<JacksonModuleRegistrar> 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 的属性。
评论