[源码学习]github.com/gin-gonic/gin
先创建一个简单的demo,执行后的调用链路在这里
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()
}
运行后,请求一下127.0.0.1:8080/ping 最终的调用链路如下:
|-goroutine-1 created by runtime.main
|-main.main
|-github.com/gin-gonic/gin.Default
|-engine.Use(Logger(), Recovery()) // 注册了两个中间件
|-github.com/gin-gonic/gin.(*RouterGroup).handle
|-github.com/gin-gonic/gin.(*Engine).Run
|-github.com/gin-gonic/gin.resolveAddress
|-net/http.ListenAndServe(address, engine.Handler()) // 这里最终还是用的net/http包起的服务
// 不同的是serverMux使用的自定义的
// engine.Handler()
|-goroutine-18 created by net/http.(*Server).Serve.func3
|-net/http.(*conn).serve
|-net/http.(*conn).readRequest
|-net/http.serverHandler.ServeHTTP
|-github.com/gin-gonic/gin.(*Engine).ServeHTTP
|-sync.(*Pool).Get // 循环利用context对象内存
|-github.com/gin-gonic/gin.(*Engine).handleHTTPRequest(c)
|-root := engine.trees[i].root // 匹配对应请求类型的tree
|-value := root.getValue(rPath, c.params, ...) // 匹配对应路由的handler
|-c.handlers = value.handlers // 设置中间件
|-c.Next() // 执行第一个中间件
|-github.com/gin-gonic/gin.LoggerWithConfig.func1
|-github.com/gin-gonic/gin.CustomRecoveryWithWriter.func1
|-main.main.func1
|-github.com/gin-gonic/gin.(*Context).Query // 获取get参数
|-github.com/gin-gonic/gin.(*Context).GetQueryArray
|-net/url.(*URL).Query // 首次调用需要实例一个map对象
|-net/url.parseQuery
|-sync.(*Pool).Put
|-net/http.(*response).finishRequest
结合上一篇的文章,我们可以发现gin的服务器流程和net/http包的差不多,只是在响应连接的时候使用了自己的serverMux。gin号称自己是内存零分配,那么在接受请求和返回数据的时候,是否真的是零分配呢?
本作品采用《CC 协议》,转载必须注明作者和本文链接