1. gin 简介
Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks to httprouter. If you need performance and good productivity, you will love Gin.
gin 是使用 golang 编写的高性能 web 开发框架
2. gin 框架重要对象
-
Context: 单次web请求的上下文对象,用于存储请求及响应等相关数据。gin从接收请求起开始构造Context,然后交由与请求对应的函数链依次进行处理并生成最后的响应 -
IRouter: 一系列管理和注册路由函数的方法集合(接口),如Use/GET/POST/Group等方法。Engine和RouterGroup都实现了IRouter接口 -
Engine:web服务的总引擎,提供服务配置、注册middleware、注册路由函数、启动服务等方法,同时也可以看做是前缀为空字符串的根RouterGroup -
RouterGroup: 方便开发者对URL进行前缀分组管理的对象,它关联了URL前缀和与之绑定的函数链。对其方法的调用本质上还是回归到对Engine对象方法的调用 -
HandlersChain: 以func(*gin.Context)为原型的函数链,既可以用来表示路由函数,也可以用来表示middleware -
HandlerFunc: 即func(*gin.Context),既可以表示路由函数,也可以表示middleware,一般情况下一个URL匹配一个路由函数(也可以是多个middleware加一个路由函数的组合),并且路由函数位于函数链的最后一个,而在路由函数之前的HandlerFunc一般都属于middleware,可用于进行参数校验、异常处理、日志打印、权限认证等用途。middleware处理完请求后需要调用且只能调用一次context.Next()方法以驱动函数链的链式执行
-
methodTrees: 请求方法树,无论是注册路由还是注册中间件,其本质就是在对应的methodTree中添加新节点。不同的请求方法将对应一棵methodTree,每棵methodTree可以看做是一个radix tree(radix tree类似于字典树,可支持路径模式匹配)。当进行路由匹配时,gin将通过对应的请求方法和请求路径去找到对应的methodTree,然后遍历methodTree找到与请求路径匹配的唯一节点node,并执行与此节点绑定的HandlersChain为什么匹配路由不使用哈希表呢?对于
web框架而言,注册路由函数的路径一般需要支持动态变量或者通配符的,例如/books/:book_id等,也就是说注册路由函数的路径是一种pattern,而哈希表无法匹配pattern,对于不同的路径将映射到唯一的哈希值
3. gin 框架关键方法
a). gin.New
返回不使用任何 middleware 的 Engine 实例
与之类似的方法是 gin.Default() ,默认注册了两个 middleware
b). RouterGroup.Use
将待注册的 middleware 添加到 RouterGroup 的函数链中
Engine 也有同样的方法,本质是为当前 Engine 实例的 RouterGroup 属性注册 middleware
c). RouterGroup.GET
只要是注册路由函数,无论是 GET/POST/PUT/PATCH/HEAD/OPTIONS/DELETE/CONNECT/TRACE/ANY 等方法,最终还是调用到 RouterGroup.Handle(httpMethod, relativePath string, handlers HandlersChain)
而 Handle 方法在对 handles 进行扩充后,将调用 engine.addRoute(method, path string, handlers HandlersChain) 对 Engine 的 methodTrees 新增节点
d). engine.ServeHttp
gin 框架是对 golang 的 http 包做了封装,在执行 Run 函数的时候就开始监听某个端口的请求了,
而对于 http.ListenAndServe 的第二个参数,它需要实现 ServeHttp 接口
在 Engine 的实现中,首先构造一个全新的 *gin.Context ,然后再将这个 Context 实例传入到对应的路由函数链进行处理
值得一提的是这里使用了协程安全的
sync.Pool进行Context对象的管理,假设请求的qps越高,那么Context对象的创建也就越频繁,这意味着gc的频率也就越高,为了避免重复的对象创建和销毁,sync.Pool将不使用的对象进行了缓存,等到下次需要使用的时候只需要调用pool.Get方法拿到缓存的对象,并且清空对象,就可以重复使用了,这减轻了golang垃圾回收的压力
通过请求路径及参数匹配请求方法树的节点,拿到相应节点的函数链,然后调用 context.Next() 驱动函数链的执行
4. 总结
-
Engine对象是配置或启动web服务的入口 -
RouterGroup对象是方便开发者对URL进行分组管理而设计的,对它的操作最终都会转换为对Engine的操作 -
Engine维护了请求方法树集合methodTrees,每注册一次URL就会在对应的请求方法树中新增节点,每次匹配请求时都需要遍历一次请求方法树以得到请求的目标节点 -
Context贯穿了请求的接受和响应,gin框架使用它在目标节点的函数链之间传递,也利用它进行函数链的驱动执行
定期推送与后端程序相关的博文
