Gin源码学习
gin.Default 源码
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}
-
Engine
- Engine是一个struct,包含了路由,中间件,配置等相关信息
- trees包含了路由和处理方法的映射,用的是类似字典树的结构
- pool 用了sync.Pool类型,来减少频繁context实例化带来的资源消耗
- RouterGroup 其中的Handlers存储了中间件的信息
- Engine是一个struct,包含了路由,中间件,配置等相关信息
-
New方法
-
初始化了Engine
-
将RouterGroup的Handlers(数组)设置成nil, basePath设置成 /
-
刚刚初始化的Engine也被赋值给了RouterGroup的engine
func New() *Engine { debugPrintWARNINGNew() engine := &Engine{ RouterGroup: RouterGroup{ Handlers: nil, basePath: "/", root: true, }, FuncMap: template.FuncMap{}, RedirectTrailingSlash: true, RedirectFixedPath: false, HandleMethodNotAllowed: false, ForwardedByClientIP: true, RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"}, TrustedPlatform: defaultPlatform, UseRawPath: false, RemoveExtraSlash: false, UnescapePathValues: true, MaxMultipartMemory: defaultMultipartMemory, trees: make(methodTrees, 0, 9), delims: render.Delims{Left: "{{", Right: "}}"}, secureJSONPrefix: "while(1);", trustedProxies: []string{"0.0.0.0/0"}, trustedCIDRs: defaultTrustedCIDRs, } engine.RouterGroup.engine = engine engine.pool.New = func() interface{} { return engine.allocateContext() } return engine }
-
-
跟New相比,Default就是默认多调用了Logger(), Recovery()
-
Use方法
-
use方法就是调用
RouterGroup.Use()
往RouterGroup.Handlers
写入记录 -
Handlers就是一个数组,用来存储中间件信息
-
注册路由的时候会用
RouterGroup
的handle
方法把路由对应的函数和之前的中间件一起放到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() }
-
handle
方法用combineHandlers
方法来把路由的中间件函数和处理函数结合到一起得到一个由HandlerFunc
组成的切片 -
HandlerFunc
是一个*Context
类型的函数type HandlersChain []HandlerFunc type HandlerFunc func(*Context)
-
-
-
中间件的执行
- Next方法遍历
HandlersChain
来执行中间件 - 中间件之间传输数据用了
c.Set()
和c.Get()
,比如我们可以在认证中间件中获取当前请求的相关信息(userID等)通过c.Set()
存入c
,然后在后续处理业务逻辑的函数中通过c.Get()
来获取当前请求的用户。c
就像是一根绳子,将该次请求相关的所有的函数都串起来了。
- Next方法遍历
路由
路由注册过程
-
第一次注册路由,例如注册a
-
继续注册一条没有公共前缀的路由,例如bc
-
注册一条与先前注册的路由有公共前缀的路由,例如bd
Run
-
通过调用 net/http 来启动服务,由于 engine 实现了 ServeHTTP 方法
-
只需要直接传 engine 对象就可以完成初始化并启动