Gin框架的设计模式-"控制反转"

1,018 阅读3分钟

背景

最近的工作内容会涉及到很多项目的"code review",侧重发现"安全漏洞"。

阅读代码时有时感觉有点费劲,我想原因一方面是对项目使用的"语言、库、框架"不熟悉,另一方面可能是缺少"设计模式"的知识,导致读一些框架代码时总是感觉"数据流"有些绕,所以我想学下"设计模式"提高代码审计的效率。

本文分析 gin框架 [1] 的Run方法,看看是否用到了什么设计模式。

分析

  • gin是什么?

    gin是go中非常流行的web框架,你可以在文档找到一个最小的例子跑起来感受一下,比如

package main

import "github.com/gin-gonic/gin"

func main() {
 r := gin.Default()
 r.GET("/ping"func(c *gin.Context) {
  c.JSON(200, gin.H{
   "message": "pong",
  })
 })
 r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

框架初始化

其中gin框架的 Run 方法实现如下:

import (
 ...
 "net/http"
 ...
)
...
func (engine *Engine) Run(addr ...string) (err error) {
 ...
 err = http.ListenAndServe(address, engine) // 调用net/http包的ListenAndServe函数,同时把Engine对象注入
 return
}

net/http 包的 ListenAndServe 函数实现如下:

func ListenAndServe(addr string, handler Handler) error {
 server := &Server{Addr: addr, Handler: handler}
 return server.ListenAndServe()  // 阻塞,等待请求
}
  • 根据这个函数调用关系可以知道,"gin框架初始化"时代码控制权从 gin框架 转移到 net/http库 。

  • 当请求过来时的代码控制权是怎么样的?

    image

    从上图左侧的函数调用链可以看到:

    * "处理请求"时代码控制权从`net/http库`转移到`gin框架`
    * `net/http库``gin框架`分层非常明显:后面的业务逻辑都是`gin框架`和业务代码处理,和`net/http库`无关
    

    net/http库 和 gin框架 之间是通过 handler.ServeHTTP(rw, req) 方法跳转的,这个 handler.ServeHTTP 是什么呢?

    hanler是一个接口类型,定义如下:

type Handler interface {
 ServeHTTP(ResponseWriter, *Request)
}
  • net/http 和 gin 框架通过 Handler 接口通信:框架初始化时, gin 向 net/http 注入"接口的具体实现";处理请求时, net/http 调用"接口的具体实现"

    按照我的理解,这就是设计模式中的"控制反转"和"依赖注入"。

  • "控制反转"和"依赖注入"是什么?

    "控制反转"就是代码控制权从业务代码"反转"到框架代码,对应到上面的场景,代码流程是从 gin -> net/http -> gin

    "依赖注入"就是"依赖的对象"不从内部创建而是从外部传递进来。对应到上面的场景, net/http库 的 ListenAndServe函数 依赖 Handler接口 ,这个接口的实现是 gin框架 传递进来的。

    那为什么需要"控制反转"和"依赖注入"呢?

  • 为什么 net/http库 要这么设计?

    通过接口通信的好处是"解耦":可以把接口理解成一种规范,net/http不关心"被调用者"是如何实现规范的。

    net/http库 负责把tcp数据解析成http请求对象,扔给 gin库 就可以了。

    如果我们也想实现一个新的go web框架,就可以实现这个接口,来处理 net/http库 解析好的http请求对象。

总结

  • net/http库 和 gin框架 的分层,是理解web框架的重要的点
  • 分析web框架时可以从两个场景入手:一方面是"框架初始化",另一方面是"请求处理"
  • "控制反转"和"依赖注入"可以实现"解耦",在框架设计时会用到

最新2021整理收集的一些高频面试题(都整理成文档),有很多干货,包含mysql,netty,spring,线程,spring cloud、jvm、源码、算法等详细讲解,也有详细的学习规划图,面试题整理等,需要获取这些内容的朋友,请点击此处 即可免费领取

20201027143218215.png