gin框架概述
- 前面写了两篇从源代码层面审视gin框架的文章,写完之后感觉结构比较乱。这里再重新总结一下
- 作为web框架,gin相对beego等更加轻量化,没有orm等内容,gin实现了路由封装,日志,鉴权等功能。核心部分,是实现RESTful规范。将http method对应的path,找到相应的handler去处理请求,最终响应http请求。
gin框架的设计思路
- golang语言的一个重要特点就是拥有高质量的官方标准库。设计web框架,自然也是离不开net/http包。下面是一个简单的http server实现。
- 上边这个例子,定义了一个struct,这个struct实现了http包的Handler接口,即ServeHTTP方法,那么,就可以把这个struct当成Handler传给ListenAndServe。
- 其实,gin框架也是这个思路,定义了名为Engine的struct,然后实现这个Engine实现了ServeHTTP方法,然后再将这个Engine作为Handler传给ListenAndServe就行。然后中间所有的路由管理,path对应的handler等,都由ServeHTTP去调用相应的实现函数。
启动Engine
- Engine作为核心的Handler,在gin框架中属于核心位置,这里贴出Engine的完整定义,重要字段的含义会在下文详细阐述。这个定义非常明显的特点就是定义了很多的bool类型的变量,很容易猜到这些bool值其实就是处理的flow的“路牌”
type Engine struct {
RouterGroup
RedirectTrailingSlash bool
RedirectFixedPath bool
HandleMethodNotAllowed bool
ForwardedByClientIP bool
AppEngine bool
UseRawPath bool
UnescapePathValues bool
MaxMultipartMemory int64
delims render.Delims
secureJsonPrefix string
HTMLRender render.HTMLRender
FuncMap template.FuncMap
allNoRoute HandlersChain
allNoMethod HandlersChain
noRoute HandlersChain
noMethod HandlersChain
pool sync.Pool
trees methodTrees
}
- 如何启动Engine呢?有了上面的例子,具体如何启动其实并不意外。
- 启动之后,http请求自然就会交给Engine的ServeHTTP来处理。但是,我们还不能马上揭开ServeHTTP的面纱,我们需要先了解gin是如何组织和管理http method, path和handler的。
gin管理method,path和handler
怎么用gin
- 在弄清楚gin如何管理method,path和handler之前,先看看,gin一般都是怎么用的。gin 例子。如果没有gin的使用经验,往下阅读之前,务必浏览这个例子。
- gin.Default会生成一个Engine对象,再由这个对象去注册相关的路由组,路由,method和handler。
路由管理——RouteGroup
-
上边Engine结构第一个变量就是继承了RouteGroup。之所以不定义新的变量,比如 rg RouteGroup来使用RouteGroup,是因为Engine需要直接使用RouteGroup实现的IRouter接口。
type RouterGroup struct { Handlers HandlersChain basePath string engine *Engine root bool }
- IRouter的Group函数的实现就是用作路由组管理。只要将正确的参数(string,HandlerFunc)传给GET,POST等方法,就可以将string对应的path,交给HandlerFunc来处理。(后边会解释HandlerFunc)
Handler是怎么设计的
- 上边的方法,HandlerFunc是重要的角色。那HandlerFunc是什么呢?
- HandlerFunc是函数类型,函数的参数是Context对象。上边链接里的例子也可以看出来,在使用gin框架时,业务逻辑的处理主要就是在自己定义的HandlerFunc里边。入参是*Context。这个Context又是啥?
- 从Context的代码注释,就可以看出Context结构在gin框架中的重要性了。请求包含的数据,响应需要的数据,在Context里边都涵盖了。
- 对比原生的http包,一个是需要实现ServeHTTP方法,一个是需要实现HandlerFunc函数。(method和function在编程里边是有区别的,千万不要混为一谈)
管理http method
- 当用户发起POST请求之后,是怎么找到注册的对应的POST方法的HandlerFunc的呢?这就要看IRouter接口的POST方法被调用的时候发生了什么。
- 上边的源码可以看出来,在整理path和handlers之后,会让engine进行addRoute操作。
- 用树结构存储path,是一个非常自然的思路。除此之外,gin框架还生成了好几棵树,每棵树对应一个http method。POST请求的话就回去POST树上边找对应的path和HandlerFunc。这个树有专业名词:基数树!
总结
- gin框架会生成几棵基数树,分别对应http method。树结构对应path的树状形态,每个path会map到一个HandlerFunc。这样,在接收到http请求的时候,先找到该请求对应的http method树,再根据URL的path找到注册好的HandlerFunc。HandlerFunc对应的业务逻辑需要gin的使用者借助Context结构自行处理。
Engine的ServeHTTP
- 有了gin管理http method,path和HandlerFunc的基础之后,我们将目光转回Engine的ServeHTTP方法当中来。
- 虽然上边的代码不难理解,但是这段代码对gin的性能影响至关重要。关键的部分在于借助sync.Pool对Context进行复用。
- 核心的处理逻辑最后交给handleHTTPRequest了。核心逻辑由源代码翻译过来就是:在接收到http请求的时候,先找到该请求对应的http method树,再根据URL的path找到注册好的HandlerFunc。HandlerFunc对应的业务逻辑需要gin的使用者借助Context结构自行处理。