likes
comments
collection
share

Swagger原理

作者站长头像
站长
· 阅读数 14

最近在基于Swagger进行二次开发, 来对项目的接口进行管理,功能实现了,但是不清楚swagger的工作原理,为了后续能更好利用Swagger来管理接口,而且能借鉴Swagger的原理,将项目中其他信息可视化展示,决定DebugSwagger的流程。版本使用的是springdoc-openapi,并不是旧版的swagger,但是口语上还是用swagger表示。

Swagger使用分两个阶段,第一个阶段是注册一些Bean,初始化一些配置。第二阶段是页面访问、接口调用,将数据填充到HTML页面展示在浏览器上。

注册静态资源

WebMvcConfigurationSupport类会实例化HandlerMapping这个Bean

Swagger原理

实例化过程中,将所有的WebMvcConfigurer中定义的ResourceHandler放到ResourceHandlerRegistry中去。所有的WebMvcConfigurer包括系统默认的和自定义的,其中和Swagger相关的就是WebMvcAutoConfiguration类的内部类WebMvcAutoConfigurationAdapter中注册的ResourceHandler,处理的URL是/webjars/**,locations是classpath:/META-INF/resources/webjars/

Swagger原理

另外一个和Swagger相关的是SwaggerWebMvcConfigurer,里面会处理/swagger-ui*/**路径,locations是classpath:/META-INF/resources/webjars/

Swagger原理

Swagger原理

ResourceHandlerRegistry注册完后,会调用ResourceHandlerRegistrygetHandlerMapping方法,实例化AbstractHandlerMapping

Swagger原理

Swagger原理

对于Swagger静态资源,对应的是ResourceHttpRequestHandler。还需要注意到,最后生成AbstractHandlerMappingSimpleUrlHandlerMapping,这在后面请求时会用到。

访问Swagger静态资源

首先访问Swagger首页地址,/swagger-ui/index.html,进入DispatcherServletdoDispatch方法,根据Request对象获取mappedHandler

Swagger原理

getHandler方法里面就是从不同的handlerMappings中获取HandlerExecutionChain,实际走的就是SimpleUrlHandlerMapping

Swagger原理

SimpleUrlHandlerMappinggetHandler方法里看,最终是在SimpleUrlHandlerMapping父类AbstractUrlHandlerMappinglookupHandler方法中,根据URL匹配出ResourceHttpRequestHandler,构造成HandlerExecutionChain对象返回。

Swagger原理

再往下根据mappedHandler获取HandlerAdapter,实际获取到的就是HttpRequestHandlerAdapter

Swagger原理

Swagger原理

接着就会调用HttpRequestHandlerAdapterhandler方法,handler方法会将请求交给HttpRequestHandlerhandleRequest方法,最终是交给ResourceHttpRequestHandlerhandleRequest方法。在该方法中,首先就是获取Resource对象。

Swagger原理

实际上是通过DefaultResourceResolverChain里面的WebJarsResourceResolverPathResourceResolver得到最终的Resource对象,首先是将swagger-ui/index.html通过WebJarsResourceResolver转成swagger-ui/4.14.0/index.html,在将转化后的URL通过PathResourceResolver解析出Resource对象。

Swagger原理

Swagger的静态资源是在org.webjars:swagger-ui:4.14.0中resources目录下

Swagger原理

最后是将Resource对象的内容,写入HttpServletResponse中返回。

访问Swagger Rest接口

访问Swagger首页时,除了一些静态资源如htmlcssjsSwagger还会访问/v3/api-docs/开头的后台Rest接口,这些接口会返回数据供页面使用,共同实现Swagger的功能。

Swagger原理

像上图的swagger-config接口完整路径是/v3/api-docs/swagger-config,这个接口是在SwaggerConfigResource类中定义的。功能就是获取所有的group和对应的URL。

下面主要介绍另外一个接口,/v3/api-docs/{group},这个接口是根据group名称获取该组下的所有接口。

接口定义是这样的

Swagger原理

首先获取OpenApiResource对象,实际获取的是OpenApiWebMvcResource对象

Swagger原理

接着调用openapiJson方法,最终调用的是AbstractOpenApiResourcegetOpenApi方法

Swagger原理

这个方法就是主要扫描接口的方法了,在openAPIService.build(finalLocale)那一句,就是扫描Controller的接口

Swagger原理

当然还有其他处理,处理参数、返回值、执行一些自定义的customisers等等(后面有时间再每一步进去看下是Swagger是如何解析接口、请求数据、返回值的),最终返回一个OpenAPI对象,然后以Json格式的字符串返回给前端。

OpenAPI这个实体类的结构如下,从官网截取部分,以便理解,有了这个结构,可以自定义一些OpenApiCustomiser,对OpenAPI对象进行改动,进行二次开发,实现一些自定义功能。

openapi: 3.0.3
info:
  title: Swagger Petstore - OpenAPI 3.0
  description: |-
    This is a sample Pet Store Server based on the OpenAPI 3.0 specification.  You can find out more about
    Swagger at [https://swagger.io](https://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!
    You can now help us improve the API whether it's by making changes to the definition itself or to the code.
    That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
  termsOfService: http://swagger.io/terms/
  contact:
    email: apiteam@swagger.io
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 1.0.11
externalDocs:
  description: Find out more about Swagger
  url: http://swagger.io
servers:
  - url: https://petstore3.swagger.io/api/v3
tags:
  - name: pet
    description: Everything about your Pets
    externalDocs:
      description: Find out more
      url: http://swagger.io
  - name: store
    description: Access to Petstore orders
    externalDocs:
      description: Find out more about our store
      url: http://swagger.io
paths:
  /pet:
    put:
      tags:
        - pet
      summary: Update an existing pet
      description: Update an existing pet by Id
      operationId: updatePet
      requestBody:
        description: Update an existent pet in the store
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'
          application/xml:
            schema:
              $ref: '#/components/schemas/Pet'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Pet'
        required: true
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'          
            application/xml:
              schema:
                $ref: '#/components/schemas/Pet'
        '400':
          description: Invalid ID supplied
        '404':
          description: Pet not found
        '405':
          description: Validation exception
      security:
        - petstore_auth:
            - write:pets
            - read:pets
    post:
      tags:
        - pet
      summary: Add a new pet to the store
      description: Add a new pet to the store
      operationId: addPet
      requestBody:
        description: Create a new pet in the store
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'
          application/xml:
            schema:
              $ref: '#/components/schemas/Pet'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Pet'
        required: true
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'          
            application/xml:
              schema:
                $ref: '#/components/schemas/Pet'
        '405':
          description: Invalid input
      security:
        - petstore_auth:
            - write:pets
            - read:pets

总结

流程还是比较清晰,Swagger提供一些Jar包,包含Rest接口和静态资源,应用启动时先注册静态资源、确定访问的URL,访问Swagger首页时,通过SpringMVC将Jar包中的静态资源取出,静态资源中请求后台Rest接口,由后台接口解析项目的Controller接口,返回接口信息给前端展示在页面上。

写这篇文章除了介绍Swagger原理,在Swagger基础上进行二次开发,另外一个目的就是是借鉴这种设计思路,和项目相关的信息可视化展示。比如项目脚本数据和数据表结构变更记录、Git文件提交记录等等。

转载自:https://juejin.cn/post/7241148626813190202
评论
请登录