gin框架分析二:gin初始化,默认配置实例构建过程

gin的函数调用流程

gin的函数调用过程大概如下图:

GIN函数调用过程第一步构建GIN实例,第二步构建GIN路由,第三步则是启动http.server包,坚挺HTTP请求,并将请求处理交给gin框架,gin又通过路由匹配寻找到对应的handler去具体处理每一个请求。

GIN的初始化过程

我们会从上面函数调用图的方法顺序开始过源码,并尝试弄清楚gin在各个阶段都干了些什么内容。

得到默认配置的gin实例

main函数代码中通过 gin.Default() 函数可以获取到一个默认配置的engine实例,Default()函数如下:

func Default() *Engine {
	debugPrintWARNINGDefault()
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
} 

debugPrintWARNINGDefault()函数首先被调用,其检测go版本是否在1.14+,如果不满足条件则给出一个警告,仅仅是一个警告而不做其他操作。

func debugPrintWARNINGDefault() {
	if v, e := getMinVer(runtime.Version()); e == nil && v <= ginSupportMinGoVer {
		debugPrint(`[WARNING] Now Gin requires Go 1.14+.

`)
	}
	debugPrint(`[WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

`)
}

通过调用New()函数,构造出一个默认配置项的engin实例。

func New() *Engine {
	debugPrintWARNINGNew()
	engine := &Engine{
		RouterGroup: RouterGroup{
			Handlers: nil,
			basePath: "/",
			root:     true,
		},
		FuncMap:                template.FuncMap{},
		RedirectTrailingSlash:  true,
		RedirectFixedPath:      false,
		HandleMethodNotAllowed: false,
		ForwardedByClientIP:    true,
		RemoteIPHeaders:        []string{"X-Forwarded-For", "X-Real-IP"},
		TrustedPlatform:        defaultPlatform,
		UseRawPath:             false,
		RemoveExtraSlash:       false,
		UnescapePathValues:     true,
		MaxMultipartMemory:     defaultMultipartMemory,
		trees:                  make(methodTrees, 0, 9),
		delims:                 render.Delims{Left: "{{", Right: "}}"},
		secureJSONPrefix:       "while(1);",
		trustedProxies:         []string{"0.0.0.0/0", "::/0"},
		trustedCIDRs:           defaultTrustedCIDRs,
	}
	engine.RouterGroup.engine = engine
	engine.pool.New = func() any {
		return engine.allocateContext()
	}
	return engine
}

 其中gin对于Context的处理使用了一个sync.Pool来处理,这样可以在每次对于Context的实例都不用重复生成,可以尽可能重复利用已经存在的实例。

engine.Use(Logger(), Recovery())方法默认为engine添加Logger和Recovery两个中间件,并保存于RouterGroup.Handlers中,然后在路由添加处理器是合并进各个路由处理中调用,这就是为什么通过gin.Default()生成实例后对于添加的路由处理方法会有3个handler的原因。

例如:

router.GET("/ping", func(c *gin.Context) {
		c.String(200, "pong %d", counter)
		counter = counter + 1
	}) 

如上路由处理对应的路由信息为:

进入engine.Use(Logger(), Recovery())方法:

func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
	engine.RouterGroup.Use(middleware...)
	engine.rebuild404Handlers()
	engine.rebuild405Handlers()
	return engine
} 

其调用父类的Use方法把默认中间件添加到RouterGroup.Handlers,同时构建了404和405的异常处理钩子函数。

至此,gin.Defaults()创建了一个包含两个默认中间件、一个可重复利用Context并在Context实例不足时生成实例的gin engin,在获得默认配置的的gin实例后接下来的任务就是构建路由树和对应的处理方法。

 

posted @ 2023-01-24 16:22  一朵野生菌  阅读(577)  评论(0编辑  收藏  举报