gin框架源码分析——路由模块

一、什么是gin框架

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是一个用Go (Golang)编写的web框架。类似于一个Martini的API,由于使用了httprouter,性能提高了40倍。如果您需要良好的表现和工作效率,您会喜欢gin。

gin框架速度很快, 这也是在企业中被广泛使用的原因之一。gin之所以能够提供高效的路由解析,是因为使用了前缀树这样的数据结构来进行path和handler方法的映射,本篇文章就来探讨gin框架的路由模块。

二、gin初始化的过程

1、Engine的实例化
Engine是容器对象,是整个框架的基础。gin提供了两个方法来创建Engine实例,New和Default方法。

// Default returns an Engine instance with the Logger and Recovery middleware already attached.
func Default() *Engine {
	debugPrintWARNINGDefault()
	//Default()方法也调用了New()方法来创建Engine实例
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
}

default方法除了包含New方法外,还增加了两个中间件,Logger是默认系统输出日志,Recovery是在报panic的时候恢复系统输出并返回500。
New()方法:

// New returns a new blank Engine instance without any middleware attached.
// By default the configuration is:
// - RedirectTrailingSlash:  true
// - RedirectFixedPath:      false
// - HandleMethodNotAllowed: false
// - ForwardedByClientIP:    true
// - UseRawPath:             false
// - UnescapePathValues:     true
func New() *Engine {
	debugPrintWARNINGNew()
	engine := &Engine{
	//RouterGroup是管理路由和中间件的组件,它定义了URL路径与处理函数的映射关系。
		RouterGroup: RouterGroup{
			Handlers: nil,
			basePath: "/",
			root:     true,
		},
		FuncMap:                template.FuncMap{},
		//RedirectTrailingSlash当前路径处理函数不存在时,是否允许重定向到路径+或-"/"的处理函数
		RedirectTrailingSlash:  true,
		//RedirectFixedPath路由未命中时,是否允许修复当前处理路径(如对路径大小写不敏感查询、删除多余路径元素等)并重定向
		RedirectFixedPath:      false,
		//HandleMethodNotAllowed路由未命中时...这个我也暂时不明白啥意思
		HandleMethodNotAllowed: false,
		//ForwardedByClientIP是否转发客户端ip
		ForwardedByClientIP:    true,
		//AppEngine如果启用该引擎,将插入一些以”X-AppEngine..."开头的标题,以便更好地与PaaS集成
		AppEngine:              defaultAppEngine,
		//UseRawPath是否使用未转义的请求路径,即url.RawPath,默认为false。如果为true,url.RawPath将用于查找参数。
		UseRawPath:             false,
		RemoveExtraSlash:       false,
		//UnescapePathValues
		UnescapePathValues:     true,
		MaxMultipartMemory:     defaultMultipartMemory,
		trees:                  make(methodTrees, 0, 9),
		delims:                 render.Delims{Left: "{{", Right: "}}"},
		secureJsonPrefix:       "while(1);",
	}
	engine.RouterGroup.engine = engine
	engine.pool.New = func() interface{} {
		return engine.allocateContext()
	}
	return engine
}

创建的Engine实例,与路由匹配相关的有RouterGroup、trees、engin.pool.New这三个参数.

三、Engine中与路由相关的参数

1.路由相关参数的调用

参数调用流程

2. 重要参数详解

(1).RouterGroup

RouterGroup结构体:

// RouterGroup is used internally to configure router, a RouterGroup is associated with
// a prefix and an array of handlers (middleware).
type RouterGroup struct {
	Handlers HandlersChain
	basePath string
	engine   *Engine
	root     bool
}

回调函数:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

Handler为中间件数组,Handler的类型为HandlersChain,是方法类型HandlerFunc的数组。HandlerFunc是参数为*Context的回调函数。

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)

// HandlersChain defines a HandlerFunc array.
type HandlersChain []HandlerFunc

注:Handler、HandlerFunc、Handle、HandlerFunc的区别:

//Handler
type Handler interface{
	ServeHTTP(ResponseWriter, *Request)
}

//HandlerFunc
type HandlerFunc func(ResponseWriter, *Request)

//Handler, 一个是方法,一个是函数 (方法是包含了接收者的函数)
func (mux *ServeMux) Handler(pattern string, handler Handler)
func Handler(pattern string, handler Handler)

//HandlerFunc,与Handler同理,一个是方法,一个是函数
func (mux *ServeMux) HandlerFunc(pattern string, callback HandlerFunc)
func HandlerFunc(pattern string, callback HandlerFunc)

Handler : Handler是一个接口,实现了ServeHTTP方法,这个ServeHHTTP方法其实就是一个回调函数,用于处理http请求。
HandlerFunc: HandlerFunc是一个回调函数类型的别名,等价于Handler的ServeHTTP方法。
Handle:用于给我们的WEB程序注册路由,传入的第二个参数是一个Handler。
HandleFunc: 与Handle一样,只不过传入的第二个参数是一个HandlerFunc。
Handle和HandleFunc基本是等价的,它们都代表了如何处理一个http请求,拿到一个Handler以及HandlerFunc,只是在使用上略微不同。

(2).trees

trees是最重要的一部分,负责路由和handler方法的映射,因为它gin框架才实现了高性能的路由匹配。
结构体类似一个key-value类型的字典树,key为字符串格式的路由,value为[]HandlerFunc,这个方法数组存储的是按顺序的中间件和handler方法。
第一部分中,gin框架创建的Engine实例,tree是make(methodTrees, 0, 9),make方法创建的切片,初始长度为0,预留总长度为9.
methodTrees和methodTree结构:

type methodTree struct {
	method string
	root   *node
}

type methodTrees []methodTree

methodTrees是[]methodTree,而methodTree是由string类型的method和node类型的指针组成。
method是HTTP的访问方法,Go中一共分为9中,也就是说methodTree数组最多有9棵树。
Go支持的的HTTP访问方法:

package http

// Common HTTP methods.
//
// Unless otherwise noted, these are defined in RFC 7231 section 4.3.
const (
	MethodGet     = "GET"
	MethodHead    = "HEAD"
	MethodPost    = "POST"
	MethodPut     = "PUT"
	MethodPatch   = "PATCH" // RFC 5789
	MethodDelete  = "DELETE"
	MethodConnect = "CONNECT"
	MethodOptions = "OPTIONS"
	MethodTrace   = "TRACE"
)

每一种方法对应一个node根节点
node的结构和类型:

type nodeType uint8

const (
	static nodeType = iota // default
	root
	param
	catchAll
)

type node struct {
    //path是当前节点的相对路径
	path      string
	//indices是目录,由所有子节点的path[0]组成的字符串
	indices   string
	//children是所有的子节点
	children  []*node
	//handlers是包括中间件的一系列当前节点的处理函数
	handlers  HandlersChain
	//priority是当前节点及子孙节点的实际路由数量,即经过该节点有多少条路径,等同于前缀树中节点的path值(一个节点的子孙节点越多,权重越大,该节点在其父节点的indices目录中越靠前,在父节点的children数组中也越靠前)
	priority  uint32
	//nType是当前节点的类型:
//nodeType分为四种类型,默认为static是普通类型节点,root是根节点,即methodTree结构体中与method一一对应的节点,param是参数路由类型的节点,即路由中可以夹带参数,例如/path/:id,:后到下一个/之前的内容会赋值给id,catchAll是匹配所有内容的路由,如/path/*id,*号后面所有的内容都会赋值给参数id,包括所有/。
	nType     nodeType
	//maxParams是子孙节点的最大参数数量
	maxParams uint8
	//wildChild是一个bool值,表示孩子节点是否有通配符
	wildChild bool
	//fullPath是所有子孙节点路径的最长前缀
	fullPath  string
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值