解析gin
框架中数据流转原理
分析流程
我们已经了解了http包中server的启动方法, 现在我们分析gin
处理流程
gin框架号称 路由提速了40倍, 所以,到底他是哪里快呢?
我们还是看下他启动服务时做哪些事情
1 |
|
和我们刚才看到的http_server非常像, 但是路由管理器这块比较强大
较高级的语法糖, 可以直接指定HTTP方法名称, 内部封装json响应实现。
我们继续从启动方法r.Run()
入手, 看下他的内部实现逻辑
1 |
|
我们可以发现, 这里仍然使用的是http包的ListenAndServe
方法, 和我们上一章调用类似,主要区别是其第二个参数, 这里是gin框架生成gin实例。
并且我们知道, 第二个参数的主要意义是, 关联路由管器对象, 即gin框架承接了url和处理函数的路由管理。
其他http请求这一套, 继续复用原生包的http
接口
我们截取下http包的server.go的代码
1 |
|
从handler.ServerHTTP
方法开始,gin框架开始接管http请求
因此我们看下gin.go中的ServerHTTP
方法
1 |
|
我们看下上面代码, 主要做以下事情
- 为减少gc重复回收, 这里使用sync.pool管理自定义Context对象
- 将请求reqeust数据copy到Context对象中, 通过Context进行管理
- 调用
engine.handleHTTPRequest
进行路由分发
在这里引入自定义的Context
对象, 其主要是用来管理数据流转过程时的,上下文数据, 比如response, request, 请求参数params,路径fullpath, 查询缓存, 错误管理, 主要的目的是:避免重复复制数据。 保证数据的一致性。这是gin最重要的数据结构体
我们着重看下 engine.handleHTTPRequest
分发内部逻辑
1 |
|
上述代码完成完整路由,进行数据的最终响应, 我们把核心代码摘出来。
1 |
|
我们先看 root.getValue
方法, 其主要进行 路由操作,这里是采用的基树Radix_tree
算法,实现较复杂,不再这里详细展开了。
我们再看下c.Next()
方法,这个方法的核心,主要是方便接入中间件(Middleware),使得代码模块化操作。
我们看下Next的具体实现
1 |
|
描述相对抽象, 我们新建一个demo例子
1 |
|
上面例子中, 我们引入一个Logger中间件, 在路由函数中打印全部路由函数名称,输出如下
1 |
|
即能看到,这里将我们新加入的Logger中间件,转换成了句柄函数,即/test
URI对应的路由函数有两个, 这两个会按照先后顺序, 依次执行。
即先执行 main.Logger.func1
, 后执行 main.main.func1
, 结合我们上面的Next
方法实现, 我们就能清楚的知道,其调用关系
实现了Next
方法的伪代码,加深理解:
1 |
|
这里比较重要的概念是, 处理函数有先后执行关系, 并且处理函数可以通过调用Abort
方法, 提前返回,不用递归调用到实际处理函数。
这些中间件,可以方便的使我们的业务代码接入权限校验auth
,日志管理
等其他功能模块。
总结
- 核心亮点: 路由管理对象的实现+ 中间件的实现原理
参考文章:
https://www.kancloud.cn/liuqing_will/the_source_code_analysis_of_gin/616920
http://www.gorillatoolkit.org/pkg/