【Gin框架】Gin框架Run起来的前后事

2023-12-25 14:22:52

Gin框架Run起来的前后事

我们使用下面代码示例来讲解Run起来的经过。

package main

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

func main() {
	r := gin.Default()
	user := r.Group("/user")
	user.GET("/info",func(c *gin.Context) {
		c.JSON(200, gin.H{
			"user": "游客",
		})
	})

user := r.Group("/admin")
	user.Use(JWTAuth)
	user.GET("/info",func(c *gin.Context) {
		c.JSON(200, gin.H{
			"user": "水洗牛仔裤",
		})
	})

	r.Run()
}

Run起来前的初始化

调用Default函数初始化了Engine结构体

type Engine struct {
	RouterGroup
	trees            methodTrees
	//省略了很多字段
}

// RouterGroup用于内部配置路由器,RouterGroup与前缀和处理程序(中间件)数组相关联。
type RouterGroup struct {
	Handlers HandlersChain
	basePath string
	engine   *Engine
	root     bool
}

RouterGroup是用来保存中间件函数的,示例代码中的Default函数使用的两个函数就被保存在GouterGroupHanlers中。

Group函数

这个函数,示例上没有,我们补充一下:

//创建一个新的路由器组。您应该添加所有具有公共中间件或相同路径前缀的路由。
//例如,可以将使用公共中间件进行授权的所有路由分组。
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
	return &RouterGroup{
		Handlers: group.combineHandlers(handlers),
		basePath: group.calculateAbsolutePath(relativePath),
		engine:   group.engine,
	}
}

他是实现路由分组的函数,basePath 这个字段就是用来储存路径的,handlers 储存中间件函数。

**注意一下:**使用Group 函数会返回一个新的RouterGroup 但是engine 还是指向之前的那一个。

调用r.Get函数时会调用EngineRouterGroup 的方法,将RouterGroup 的路径和中间件函数与r.Get 中的路径与处理函数结合。

这个时候这个路由的路径是完整的,并且访问路由所需要的调用的函数也是完整的。

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()
}

最后调用addRoute 方法通过前缀树路径匹配,将节点添加到前缀树上。

 type methodTree struct {
	method string
	root   *node
}

type methodTrees []methodTree

type node struct {
	path      string
	indices   string
	wildChild bool
	nType     nodeType
	priority  uint32
	children  []*node // child nodes, at most 1 :param style node at the end of the array
	handlers  HandlersChain   
	fullPath  string
}

Gin的路由树是一个切片+前缀树组成的。可以理解为一个方法一颗树,如Get方法对应Get前缀树,

Post方法对应Post前缀树,这样处理让Gin的路由简单的实现了**RESTful API 。**

这个例子生成的前缀树如下图:

user下的info中有三个函数:Logger,Recovery和处理函数。

admin下的info有四个函数:Logger,Recovery,JWTAuth和处理函数。

Run起来后的二三事

Run函数的作用是调用http.ListenAndServe去监听设置的地址端口。

这里咱们用一个思维导图去梳理Run干了什么事:

在这里插入图片描述

net.Listen 创建一个网络监听器。

l.Accept 创建一个网络连接器。

c.Serve(ctx) 开启一个客户端连接。在for循环中,每一个连接都会创建一个新的协程去处理。

serverHandler{c.server}.ServeHTTP(w, w.req) 这个结构是创建了一个serverHandler结构体设置字段值。

handler.ServeHTTP(rw, req) 回到Gin框架,初始化gin.Context,获取http.ResponseWriter

*http.Request 的数据。

handleHTTPRequest 获取对应的方法树。这个匹配的过程和前缀树插入的过程很相似,可以查查看看。

getValue 由路径获取方法前缀树上对应的节点。

[c.Next]调用节点上函数链的第一个函数。经过链式调用完成所有的工作。

连接的过程存在go的Context贯穿整个过程。在此没有解释,后续会写一篇关于Context的文章。

文章来源:https://blog.csdn.net/m0_50562814/article/details/132796264
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。