Go 框架解析 -iris_一个北漂的程序猿

伊丽莎白-简 等级 323 0 0

文章目录

前言

之前已经发过一篇过于beego的文章《golang框架解析-beego》,今天带来的是go框架iris的解析,主要讲解iris框架的一个生命周期过程。

在读这篇文章之前,如果没看过《golang框架解析-beego》的可以先去看看,因为《golang框架解析-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的生命周期

Go 框架解析 -iris_一个北漂的程序猿

图片过大 建议查看原图片链接 http://cdn.tigerb.cn/20190628234814.png

上图是我在读iris代码时,整理的iris框架的一个生命周期流程图,内容比较多。总的来说划分为四个大的部分:
橙色部分:
初始化iris.Application:

  • 创建iris.Application
  • 创建APIBuilder(app.Get()等方法的路由都是注册到这里)
  • 创建Router(每个http请求都是通过router处理的)

蓝色部分:
注册路由到app.APIBuilder
紫色部分:
初始化一个http.Server
绿色部分:
构建路由handler&启动http server:

  • 注册 app.APIBuilder.routes 的路由到 app.Router.requestHandler
  • 注册 app.APIBuilder 到 app.Router.routesProvider
  • 启动 http server

关键代码解析

  1. 创建一个iris Application
// Application 首先看看我们的iris Application结构体组成
type Application struct {
    // 我们的路由都注册到了 APIBuilder
    *router.APIBuilder
    // *router.Router 实现了ServeHTTP方法 并且最终赋值给了&http.server{}.Handler
    *router.Router
    // 请求上下文池子
    ContextPool    *context.Pool
    // 配置项
    config    *Configuration
    // 日志
    logger    *golog.Logger
    // 视图
    view    view.View
    // 执行一次的once
    once    sync.Once
    // 互斥锁
    mu    sync.Mutex
    Hosts            []*host.Supervisor
    hostConfigurators    []host.Configurator
}

// 创建了一个iris应用实例
// 为什么不直接New呢?
// 因为Default里面注册了两个handle
// 1. recover panic的方法,
// 2. 请求日志
app := iris.Default()

func Default() *Application {
    app := New()
    // 合成复用*APIBuilder的Use
    app.Use(recover.New())
    // 合成复用*APIBuilder的Use
    app.Use(requestLogger.New())

    return app
}

// app := New() 得到的结构体
app := &Application{
    config:     &config,
    logger:     golog.Default,
    // 很关键:我们的路由都注册到了 APIBuilder
    APIBuilder: router.NewAPIBuilder(),
    // 很关键:*router.Router 实现了ServeHTTP方法 并且最终赋值给了&http.server{}.Handler
    Router:     router.NewRouter(),
}

// 注册api请求的中间件
func (api *APIBuilder) Use(handlers ...context.Handler) {
    api.middleware = append(api.middleware, handlers...)
} 
  1. 关于router.NewAPIBuilder()
    APIBuilder的routes属性很关键,最终的我们定义的路由都是注册到了这里。
// APIBuilder
api := &APIBuilder{
    macros:            macro.Defaults,
    errorCodeHandlers: defaultErrorCodeHandlers(),
    reporter:          errors.NewReporter(),
    relativePath:      "/",
    // 最终的我们定义的路由都是注册到了这里
    routes:            new(repository),
}

// repository的结构
type repository struct {
    routes []*Route
} 

结论:用户路由注册到了app.APIBuilder.routes

  1. 关于router.NewRouter()

router.NewRouter()返回的是一个&Router{}指针,&Router{}有三个很关键的属性和一个ServeHTTP成员方法。

三个关键的属性:

  • ainHandler 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 // 每次http请求都会执行mainHandler mainHandler http.HandlerFunc wrapperFunc func(http.ResponseWriter, *http.Request, http.HandlerFunc)

cPool          *context.Pool r
routesProvider RoutesProvider

}

// implement ServeHTTP func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) { // 每次http请求都会执行mainHandler router.mainHandler(w, r) }


结论:每次http请求都会执行mainHandler

4.  注册路由

这里很简单了就是注册用户路由到app.APIBuilder.routes

//router 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, }


5.  构建请求handler

//启动路由 app.Run() ⬇️ // 构建 app.Build() ⬇️ // 构建路由 app.Router.BuildRouter(app.ContextPool, routerHandler, app.APIBuilder, false) ⬇️ // 构建请求Handler // 把app.APIBuilder注册的api注册到了requestHandler里 // 因为我们在下面发现请求都是从router.requestHandler去处理的 requestHandler.Build(routesProvider) ⬇️ // 赋值 router.requestHandler = requestHandler router.routesProvider = routesProvider ⬇️ // the important 没错很重要的地方mainHandler被赋值的地方 // 也就是accpet请求实际执行的代码 // 真相就在这 // the important 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)


6.  启动HTTP Server

最后我们就是启动这个http server了,这里和绝大多数golang的http服务启动基本一致。

// 赋值http服务的ip+port iris.Addr(":8888") ⬇️ //创建http.Server并启动服务的匿名方法 func Addr(addr string, hostConfigs ...host.Configurator) Runner { return func(app *Application) error { return app.NewHost(&http.Server{Addr: addr}). Configure(hostConfigs...). ListenAndServe() } } ⬇️ // app.NewHost(&http.Server{Addr: addr}) // 就是这里赋值app.Router给http.Server的Handler的 if srv.Handler == nil { srv.Handler = app.Router } ⬇️ // 启动服务 su.Server.Serve(l) ⬇️ // accept请求 l.Accept() ⬇️ // 启动一个goroutine处理请求 go c.serve(ctx) ⬇️ // 最终至此真相都大白了 serverHandler{c.server}.ServeHTTP(w, w.req)

```

结语

最后我们再简单的回顾下上面的流程:

Go 框架解析 -iris_一个北漂的程序猿

文献

https://mp.weixin.qq.com/s/-xhhuPkutY1-G4\_NugNotQ

本文转自 https://blog.csdn.net/itqingliang/article/details/105650738,如有侵权,请联系删除。

收藏
评论区

相关推荐

Golang高阶:Golang1.5到Golang1.12包管理
版权所有,转载请注明:http://www.lenggirl.com/go/gomod.html(https://links.jianshu.com/go?tohttp%3A%2F%2Fwww.lenggirl.com%2Fgo%2Fgomod.html) 1. 前言 Golang 是一门到如今有十年的静态高级语言了,2009年的时
Golang高并发抓取HTML图片
版权所有,转载请注明:http://www.lenggirl.com/language/gopicture.html(https://links.jianshu.com/go?tohttp%3A%2F%2Fwww.lenggirl.com%2Flanguage%2Fgopicture.html) 使用准备 1.安装Golang 2.
Golang指南:顶级Golang框架、IDE和工具列表
自推出以来,Google的Go编程语言(Golang)越来越受主流用户的欢迎。在2016年12月的一份调研中,3,595名受访者中有89%表明他们在工作中或工作以外用Go语言编程。 此外,在编程语言中,Go语言在专业知识和偏好方面排名最高。2017年7月,在Tiobe的年度编程语言排名(https://www.tiobe.com/tiobeindex
【Golang】Golang + jwt 实现简易用户认证
<p本文已同步发布到我的个人博客:<a href"https://links.jianshu.com/go?tohttps%3A%2F%2Fglorin.xyz%2F2019%2F11%2F23%2FGolangjwtsimpleauth%2F" target"_blank"https://glorin.xyz/2019/11/23/Golang
golang 中神奇的 slice
声明:本文仅限于简书发布,其他第三方网站均为盗版,原文地址: golang 中神奇的 slice(https://links.jianshu.com/go?tohttps%3A%2F%2Fliqiang.io%2Fpost%2Fimagesliceingolang) 在 golang 中,似乎人们都不太喜欢使用 Linked List,甚至于原
godoc 命令和 golang 代码文档管理
介绍 godoc 是 golang 自带的文档查看器,更多的提供部署服务 go doc 和 godoc 在 golang 1.13 被移除了,可以自行安装 golang.org go1.13 godoc(https://links.jianshu.com/go?tohttps%3A%2F%2Fgolang.org%2Fdoc%2Fg
为什么GOPROXY对Golang开发如此重要
为什么GOPROXY对Golang开发如此重要 引言 从Go 1.13开始,Go Module作为Golang中的标准包管理器,在安装时自动启用,并附带一个默认的GOPROXY。 但是对于其他的GOPROXY选项,比如JFrog GoCenter,以及你自己的Go Module包,你需要在公众视野中保持安全,你应该选择什么样的配置? 你怎样才能
【Golang】GoWeb框架之Gin-简明教程
Gin 简介 Gin is a HTTP web framework written in Go (Golang). It features a
Golang中常用的字符串操作
Golang中常用的字符串操作 一、标准库相关的Package go import( "strings" ) 二、常用字符串操作 1. 判断是否为空字符串 1.1 使用“”进行判断 思路:直接判断是否等于""空字符串,由于Golang中字符串不能为 nil,且为值类型,所以直接与空字符串比较即可。 举例: go
Go 框架解析 -iris_一个北漂的程序猿
文章目录 前言(about:blank_1) 安装(about:blank_6) iris的生命周期(about:blankiris_32) 关键代码解析(about:blank_53) 结语(about:blank_268) 文献(about:blank_272) (https://blo
Go Iris学习笔记01
Iris MVC支持 文档: 支持所有 HTTP 方法, 例如,如果想要写一个 GET 那么在控制器中也要写一个 Get() 函数,你可以在一个控制器内定义多个函数。 每个控制器通过 BeforeActivation 自定义事件回调,用来自定义控制器的结构的方法与自定义路径处理程序,如下:(还未实验) func (m
深入理解 Go Slice
(https://imghelloworld.osscnbeijing.aliyuncs.com/0ce8a8773a658d4b843e5796a0dbf001.png) image 原文地址:深入理解 Go Slice(https://github.com/EDDYCJY/blog/blob/master/golang/pkg/20
iris-session梳理
入口 api : iris.New() api.Adapt(gm.NewSession()) session的构造 go func NewSession() sessions.Sessions { db : redis.New(rs.Config{Network: rs.DefaultRedisNetwork, Ad
我的golang基础
库查询 https://gowalker.org/你应该$HOME/.profile文件增加下面设置。 搭建go的环境 step1:去golang的官网下载go的安装包 windows:go1.9.2.....msi mac:go1.9.2......pkg 双击傻瓜式安装 linux:go1.9.2.linuxamd64.tar.gz 默认到下
go get下载包失败问题
关于我由于某些不可抗力的原因,国内使用go get命令安装包时会经常会出现timeout的问题。本文介绍几个常用的解决办法。 从github克隆golang在github上建立了一个镜像库,如https://github.com/golang/net就对应是 https://golang.org/x/net的镜像库。 要下载golang.org/x/net包

热门文章

简说设计模式——外观模式Go Iris学习笔记01

最新文章

Go Iris学习笔记01简说设计模式——外观模式