go

gin

gin 从路由响应函数看Engine和Context的关系

Posted by Liangjf on July 20, 2020

gin 从路由响应函数看Engine和Context的关系

g.POST("/v1/push", controllers.PushMsg)
func PushMsg(c *gin.Context) {

}

Engine gin的抽象实例

type Engine struct {
	RouterGroup
	...
	allNoRoute       HandlersChain
	allNoMethod      HandlersChain
	noRoute          HandlersChain
	noMethod         HandlersChain
	trees            methodTrees
}

包含了路由管理和配置结构RouterGroup, 路由树等

Engine的工作是实例化gin, 管理注册路由, 运行web服务, 请求触发响应, 拥有请求的所有客户端信息和持有net.conn

Context 结构

type Context struct {
	writermem responseWriter
	//http原生包的读写字段
	Request   *http.Request
	Writer    ResponseWriter
	
	Params   Params
	handlers HandlersChain
	
	//gin Engine结构
	engine *Engine
}

Context是gin的上下文结构, 在整个请求的生命周期有效, 并且看到Context引用了Engine, 因此在触发http请求时, Context也拥有Engine的能力(可以调用暴露的接口)

看这里, gin在实例化Engine的时候, 会创建一个申请Context的对象池

func New() *Engine {
	debugPrintWARNINGNew()
	engine := &Engine{
		...
	}
	engine.RouterGroup.engine = engine
	engine.pool.New = func() interface{} {
		return engine.allocateContext()
	}
	return engine
}

创建Context对象, 传入engine到内部

func (engine *Engine) allocateContext() *Context {
	return &Context{engine: engine}
}

ServeHTTP是gin Engine实现http包接口, 也是能够无缝接入http原生的依赖, 也是gin开始发威的开始.

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

可以看到, 里面就是从Context对象池中申请Context, 然后传入handleHTTPRequest, 直至传到最后的路由响应, 最后归还Context到对象池

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	c := engine.pool.Get().(*Context)
	c.writermem.reset(w)
	c.Request = req
	c.reset()

	engine.handleHTTPRequest(c)

	engine.pool.Put(c)
}

总结

  • Engine是实例化gin, 管理注册路由, 运行web服务, 请求触发响应, 拥有请求的所有客户端信息和持有net.conn
  • Context是gin的上下文结构, 在整个请求的生命周期有效, 并且看到Context引用了Engine, 因此在触发http请求时, Context也拥有Engine的能力(可以调用暴露的接口)