Go框架解析:iris
2019-06-29
前言
报了个驾校,时隔两个多月没发文章了,驾考上周终于都结束了,这之后得补补前两月的文章了。之前定了个目标,读完beego、iris、gin等go框架的源码,之前已经发过一篇过于beego的文章Go框架解析:beego,今天带来的是go框架iris的解析,主要讲解iris框架的一个生命周期过程。
在读这篇文章之前,如果没看过Go框架解析:beego的可以先去看看,因为Go框架解析:beego有讲关于go如何启动一个http server,这个知识点对理解本篇文章有很大的帮助。
安装
使用glide安装:
glide get github.com/kataras/iris glide get github.com/kataras/golog
|
启动一个简单的iris http服务:
//main.go package main
import "github.com/kataras/iris"
func main() { app := iris.Default() app.Get("/ping", func(ctx iris.Context) { ctx.JSON(iris.Map{ "message": "pong", }) }) app.Run(iris.Addr(":8888")) }
|
iris的生命周期
访问图片源地址查看大图 https://blog-1251019962.cos-website.ap-beijing.myqcloud.com/qiniu_img_2022/20190628234814.png
上图是我在读iris代码时,整理的iris框架的一个生命周期流程图,内容比较多。总的来说划分为四个大的部分:
橙色部分
初始化iris.Application:
- 创建iris.Application
- 创建APIBuilder(app.Get()等方法的路由都是注册到这里)
- 创建Router(每个http请求都是通过router处理的)
蓝色部分
注册路由到app.APIBuilder
紫色部分
初始化一个http.Server
绿色部分
构建路由handler&启动http server:
- 注册
app.APIBuilder
到app.Router.routesProvider
- 注册
app.APIBuilder.routes
的路由到app.Router.requestHandler
- 启动http server
关键代码解析
- 创建一个iris Application
type Application struct { *router.APIBuilder *router.Router ContextPool *context.Pool config *Configuration logger *golog.Logger view view.View once sync.Once mu sync.Mutex Hosts []*host.Supervisor hostConfigurators []host.Configurator }
app := iris.Default()
func Default() *Application { app := New() app.Use(recover.New()) app.Use(requestLogger.New()) return app }
app := &Application{ config: &config, logger: golog.Default, APIBuilder: router.NewAPIBuilder(), Router: router.NewRouter(), }
func (api *APIBuilder) Use(handlers ...context.Handler) { api.middleware = append(api.middleware, handlers...) }
|
- 关于
router.NewAPIBuilder()
APIBuilder的routes属性很关键,最终的我们定义的路由都是注册到了这里。
api := &APIBuilder{ macros: macro.Defaults, errorCodeHandlers: defaultErrorCodeHandlers(), reporter: errors.NewReporter(), relativePath: "/", routes: new(repository), }
type repository struct { routes []*Route }
|
结论:用户路由注册到了app.APIBuilder.routes
- 关于
router.NewRouter()
router.NewRouter()
返回的是一个&Router{}
指针,&Router{}
有三个很关键的属性和一个ServeHTTP
成员方法。
三个关键的属性:
mainHandler http.HandlerFunc
requestHandler RequestHandler
routesProvider RoutesProvider
我们再看成员方法ServeHTTP
实现了ServeHTTP(w http.ResponseWriter, r *http.Request)
方法,就是accept请求之后就会执行这个方法,我们看看具体方法内容。
// implement ServeHTTP func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) { // 所以这里可以看出accept请求之后会执行mainHandler router.mainHandler(w, r) }
|
func NewRouter() *Router { return &Router{} }
type Router struct { mu sync.Mutex requestHandler RequestHandler mainHandler http.HandlerFunc wrapperFunc func(http.ResponseWriter, *http.Request, http.HandlerFunc)
cPool *context.Pool r routesProvider RoutesProvider }
func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) { router.mainHandler(w, r) }
|
结论:每次http请求都会执行mainHandler
- 注册路由
这里很简单了就是注册用户路由到app.APIBuilder.routes
func (api *APIBuilder) Get(relativePath string, handlers ...context.Handler) *Route { return api.Handle(http.MethodGet, relativePath, handlers...) }
route := &Route{ Name: defaultName, Method: method, methodBckp: method, Subdomain: subdomain, tmpl: tmpl, Path: path, Handlers: handlers, MainHandlerName: mainHandlerName, FormattedPath: formattedPath, }
|
- 构建请求handler
app.Run() ⬇️
app.Build() ⬇️
app.Router.BuildRouter(app.ContextPool, routerHandler, app.APIBuilder, false) ⬇️
requestHandler.Build(routesProvider) ⬇️
router.requestHandler = requestHandler router.routesProvider = routesProvider ⬇️
router.mainHandler = func(w http.ResponseWriter, r *http.Request) { ctx := cPool.Acquire(w, r) router.requestHandler.HandleRequest(ctx) cPool.Release(ctx) } ⬇️
func (h *routerHandler) HandleRequest(ctx context.Context)
|
- 启动HTTP Server
最后我们就是启动这个http server了,这里和绝大多数golang的http服务启动基本一致。
iris.Addr(":8888") ⬇️
func Addr(addr string, hostConfigs ...host.Configurator) Runner { return func(app *Application) error { return app.NewHost(&http.Server{Addr: addr}). Configure(hostConfigs...). ListenAndServe() } } ⬇️
if srv.Handler == nil { srv.Handler = app.Router } ⬇️
su.Server.Serve(l) ⬇️
l.Accept() ⬇️
go c.serve(ctx) ⬇️
serverHandler{c.server}.ServeHTTP(w, w.req)
|
结语
最后我们再简单的回顾下上面的流程:
《Go框架解析:系列文章链接如下: