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 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<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。
@Component
public 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
@Configuration
public 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 的属性。
评论