gin框架handler注册流程原理

什么是gin框架

gin框架是一个用于构建 Web 应用程序的 Go 语言框架。它旨在提供一种简单,快速的方式来构建 Web 应用程序。Gin 使用了一种名为底层感知(low-level awareness)的技术,可以最大化应用程序的性能。Gin 还具有丰富的中间件(middleware)库,可以方便地扩展应用程序的功能。

git地址

https://github.com/gin

如何使用gin框架

如何在项目中使用该命令:go get -u github.com/gin-gonic/gin
如果下载超时 可以使用代理解决 查看上一篇文章https://www.jianshu.com/p/b6cdab0b852f

代码

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    //1.创建  engine对象
    engine := gin.Default()
    engine.Use(middleware)
    //2.设置请求路径
    engine.GET("/hello", func(ctx *gin.Context) {
        ctx.JSON(200, gin.H{"data":"hello"})
    })

    //3. 设置端口启动
    if err := engine.Run(":8081"); err != nil {
        recover()
    }

}

通过上述代码片段服务已经可以使用,可以访问http:127.0.0.1:8088/hello即可获得服务端返回的数据。

原理解读

注册engine

我们从上述代码中可以看出使用gin.Default()方法创建engine对象,大致原理为:

func Default() *Engine {
    //...
    engine := New()
    //...
    return engine
}

我们可以看出来Default方法中使用New()方法创建engine对象,具体的详情如下展示:

func New() *Engine {
     // ...
    //创建engine 实例
    engine := &Engine{
        RouterGroup: RouterGroup{
            Handlers: nil,
            basePath: "/",
            root:     true,
        },
        // ...
        // 9 棵路由压缩树,对应9种http方法
        trees:                  make(methodTrees, 0, 9),
        // ...  
    }
    engine.RouterGroup.engine = engine
    // engine.Context 对象池
    engine.pool.New = func() any {
        return engine.allocateContext(engine.maxParams)
    }
    return engine
}

我们大概可以看出,在创建engine实例,中可以看到有9种压缩树对应的http的9种请求方式。

注册middleware

通过engine.Use()方法可以实现中间件的注册,会将注册的middleware添加RouterGroup.handles中。后续RouterGroup下注册的handle都会在前缀中拼上这部分group公共的handles。

func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
    engine.RouterGroup.Use(middleware...)
    //...
    return engine
}
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
    group.Handlers = append(group.Handlers, middleware...)
    return group.returnObj()
}

handler注册流程

图1.png

我们以http Get请求为例子handler的注册流程为先调用handle方法,然后通过3步骤:第一步主要判断注册的路径属于哪个路由组,路由组下有部分的公共的参数被该路由组所公用,在该路由组下选择对应的basepath,作为公共的前缀,根据公共浅醉拼接上自身的路径可以得到一个完整的路径。第二步主要是将注册的handles链时,先获取到routeGroup组中公用的中间件获取到,拼接到注册的handles, 形成一个完整的handles链。第三步,会选择对应的压缩前缀树检索,如果有节点就复用,如果没有就创建。

前缀树

Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。
典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。
它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较。

如图2所示该图就是一个前缀树。


图2

压缩前缀树

压缩前缀树是在前缀树的基础上多了一个条件某个子节点是其父节点的唯一孩子,则与父节点进行合并

如图3所示,我们在树种插入ABC,ABCD,BCD,压缩树在进行压缩的时候首先根据我们上面将的规则进行压缩,某个子节点是其父节点的唯一孩子,则与父节点进行合并 可以看到压缩后将 BCD进行了压缩,有人会问为什么不能将CD进行压缩,因为如果将CD压缩为一个节点,那么ABC就失效了。

图3

gin框架也采用了压缩前缀树的数据结构

采用压缩前缀树相对于map结构是有几点优势的:
第一:压缩前缀树更容易处理处理通配,例如:/ping/,/user/*,
第二:压缩前缀树相对于map更加的节省空间
第三:map检索和数量量有关系,前缀树和数据长度有关
通过这3点可以看出压缩前缀树在该场景下更加有优势。

gin框架还对压缩前缀树做了策略调整,将链路相对较长的链路放到树的最左边,方便检索。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容