Gin源码阅读 01

168 阅读2分钟

Clone源码

git clone git@github.com:gin-gonic/gin.git

run gin

阅读之前,首先要尝试使用一下。

但是Gin作为依赖库,并没有main方法入口,所以无法直接运行。

我选择创建main package,写一个简单demo以运行Gin框架。

从官方文档,可以看到如下示例:

func main() {
  r := gin.Default() //创建上下文
  r.GET("/ping", func(c *gin.Context) { //添加路由
    c.JSON(http.StatusOK, gin.H{
      "message": "pong",
    })
  })
  r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

在在源码根目录下创建main文件夹,创建main.go,添加以上代码。

# 进入main目录
cd main
# 启动demo
go run .
# 访问ping接口
curl http://127.0.0.1:8080/ping

控制台可以成功地输出pong

gin.Default()

gin.go文件,可以找到Default方法的源码

// Default returns an Engine instance with the Logger and Recovery middleware already attached.
func Default() *Engine {
   debugPrintWARNINGDefault()
   engine := New()
   engine.Use(Logger(), Recovery())
   return engine
}

使用了New()方法创建了一个 Engine 类型实例。

不妨先看看 Engine 类型的定义:

type Engine struct {
   RouterGroup
   ...
}

我觉得一些配置参数可以先忽略,可以看到结构体Engine继承自RouterGroup类型,这很重要,因为demo中下一步添加路由就使用了。

type RouterGroup struct {
   Handlers HandlersChain
   basePath string
   engine   *Engine
   root     bool
}

RouterGroup 类型的定义中一个有趣的点是,包含了一个 Engine 类型成员。此时再来看 New() 方法,

func New() *Engine {
   debugPrintWARNINGNew()
   engine := &Engine{
      RouterGroup: RouterGroup{
         Handlers: nil,
         basePath: "/",
         root:     true,
      },
      ...
   }
   engine.RouterGroup.engine = engine //把自身引用赋值给父类RouterGroup的成员engine
   engine.pool.New = func() any {
      return engine.allocateContext()
   }
   return engine
}

可以发现,在实例化 Engine 的过程中,把自身引用赋值给了父类RouterGroup的成员engine。

engine.Get()

在demo的添加路由过程中,调用了实例engine的Get()方法,查看源码

rountergroup.go

func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
   return group.handle(http.MethodGet, relativePath, handlers)
}

func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
   absolutePath := group.calculateAbsolutePath(relativePath)
   handlers = group.combineHandlers(handlers)
   group.engine.addRoute(httpMethod, absolutePath, handlers)
   return group.returnObj()
}

发现Get定义在RouterGroup类型中,是可以直接通过子类型调用父类型的方法的。