关于 swagger plugin 的简单介绍与运用

之前用 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 自带的实现,我觉得如果真的要做,还是要自己动手尝试一下的.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,796评论 6 342
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,949评论 25 707
  • 南下秦中八百里,高风吹过剑门关。 浮星慢涌出重岭,撵月疾行照阔川。 勿道如今巴水劲,犹说自古蜀山难。 吟诗不取梓州...
    长安旧人阅读 495评论 3 15
  • 第一次听说你,是在小学四年级。你在一班,我在三班。 那年运动会,我们班都在议论一班转来一位新同学,跳高非常厉害...
    ssssssyyyyyylll阅读 707评论 7 6