背景
最近的工作内容会涉及到很多项目的"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) }
gin框架的
Engine
实现了这个接口,所以最终调用的是"框架初始化"时"注入"的"Engine对象"的ServeHTTP
方法。所以小结一下:
* 框架初始化时,代码流程是 `gin` -> `net/http` * 请求过来时,代码流程是 `net/http` -> `gin`
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框架时可以从两个场景入手:一方面是"框架初始化",另一方面是"请求处理"
-
"控制反转"和"依赖注入"可以实现"解耦",在框架设计时会用到
感谢大家的阅读!希望本文对大家有所帮助。最后,有想学习本文源码笔记以及更多java高级学习课程,面试资料的小编已经整理打包成一个文档!要获取的小伙伴点赞私信回复学习即可免费领取!
原文出处:Gin框架的设计模式-"控制反转"