之前用 swagger 都是简单的使用,没有考虑过 swagger 具体的实现,不过这一篇文章也并没有介绍 swagger 的具体实现,而是从 swagger 的 plugin 切入,研究自定义 swagger plugin 的问题
我们知道 swagger 集成进 spring 或 spring-boot 是通过@EnableSwagger2或者是在 spring-servlet.xml 中增加一个bean 的配置(具体这些都可以去网上随便搜搜都有了),然后通过点击进@EnableSwagger2进去可以看见这个注解的具体实现过程,这里有一篇博客,介绍的挺详细的
http://blog.csdn.net/qq_25615395/article/details/70229139
然后这里介绍一下这篇文章里没有涉及到的,或者说是没有展开讲的内容,关于plugin 的使用.
swagger 通过@EnableSwagger2这个注解进去(或者 spring-servlet.xml 中添加的 bean),会到一个 SpringSwaggerConfig 的类中,这个类是 swagger 的配置类,比较重要的这里面配置了一个 swaggerPluginAdapter的 bean
public class SwaggerPluginAdapter implements ApplicationListener<ContextRefreshedEvent>
这个bean 实现了ApplicationListener 这个接口的onApplicationEvent方法
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
if (initialized.compareAndSet(false, true)) {
log.info("Context refreshed");
ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();
Map<String, SwaggerSpringMvcPlugin> plugins = BeanFactoryUtils.beansOfTypeIncludingAncestors(
applicationContext,
SwaggerSpringMvcPlugin.class);
if (plugins.isEmpty()) {
log.info("Did not find any SwaggerSpringMvcPlugins so creating a default one");
new SwaggerSpringMvcPlugin(springSwaggerConfig)
.build()
.initialize();
} else {
log.info("Found custom SwaggerSpringMvcPlugins");
for (Map.Entry<String, SwaggerSpringMvcPlugin> entry : plugins.entrySet()) {
if (entry.getValue().isEnabled()) {
log.info("initializing plugin bean {}", entry.getKey());
entry.getValue()
.build()
.initialize();
} else {
log.info("Skipping initializing disabled plugin bean {}", entry.getKey());
}
}
}
} else {
log.info("Skipping SwaggerSpringMvcPlugin initialization already initialized!");
}
}
这段代码的核心大概是在应用的上下文中去找,有没有满足设定条件的 plugin,如果没有,则 swagger 会自己建一个默认的,这个默认的也就是平时我们使用的,所以在这里,我们就可以做一些自定义的工作.做这些工作,需要创建一个继承SwaggerSpringMvcPlugin的类和一个自定义的SwaggerConfig 类(这个类也就是在 spring-servlet.xml 中创建成 bean的那个类)
首先我们需要创建一个继承于SwaggerSpringMvcPlugin的类,并将这个类注射成应用上下文中的bean,在创建这个bean 的时候,需要注意的是得要注入SwaggerSpringConfig 这个类.当在应用上下文中注入了SwaggerSpringMvcPlugin这个 bean 之后,在上面那段代码中就可以监测到上下文中有自定义的 plugin,则就会跑到下面那部分.
所以自定义的 plugin 类需要重写父类的 build 方法和initialize方法,这两个方法中的就是 plugin 类的核心代码实现
public SwaggerSpringMvcPlugin build() {
if (initialized.compareAndSet(false, true)) {
configure();
buildSwaggerGlobalSettings();
buildApiListingReferenceScanner();
buildSwaggerApiResourceListing();
}
return this;
}
protected void initialize() {
if (enabled) {
this.build().swaggerApiResourceListing.initialize();
}
}
后面部分的代码其实沿着源码一路点下去,就可以看见具体的实现过程,这里也大致讲一下.有两个部分,一个是 ApiResourceListing,一个是 ApiListingReferenceScanner,前面是对使用了@Api 注解的类进行扫描,并解析,后面一个是从前面解析的类中,把使用了@ApiOperation 注解的方法找出来并解析,所以很容易想到,如果需要加入特殊的类扫描注解,可以使用自定义的ApiResourceListing,如果需要加入特殊的方法的注解,就自定义 scanner 就好了.包括swagger 中的各个注解,都是从 ApiListingReferenceScanner这个类中引申开来,这里贴一下源码中关于这部分的代码结构,感兴趣的可以点进去一个一个的看看,这些也都是可以由用户自己自定义的
额,不会贴图,凑合看吧,都很好找到的...
通过这一些的方法出来之后,会到ApiResourceListing这个类中
swaggerCache.addSwaggerResourceListing(swaggerGroup, resourceListing);
的这一句代码,这里就是将解析好的resourceListing,添加到 swaggerCache 之中去,swaggerGroup 是用户通过配置文件添加的组名,这个没啥,关键是 swaggerCache,我之前也不是很懂这个到底是干嘛的,不过看源码的时候,可以知道resourceListing里面已经是把所有带有注解的类和方法的有用信息都提取出来保存在一个model 中,所以估计 swaggerCache 应该是存放这些信息并在其他地方通过这个 cache 获取到这些信息并创建我们熟知的 swagger 页面的,去查了一下大概,差不多也就是这个意思,这个就属于 swagger 实现原理的后一半部分了,这里也就不赘述了,还是那句话,感兴趣可以去 Google 一下,应该都有的.
这里主要也就是讲一个思路,所以具体代码没有贴,贴的也都是 swagger 自带的实现,我觉得如果真的要做,还是要自己动手尝试一下的.
网友评论