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的能力(可以调用暴露的接口)