Gin源码分析-启动过程详解

gin的初始化十分简单,我们通过如下请求就可以完成一个简单的gin服务的启动。

func main() {
  r := gin.Default()    // 加载gin引擎
  // 注册路由
  r.GET("/ping", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{
      "message": "pong",
    })
  })
  // 启动Gin Server
  r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

创建Engine对象

func Default() *Engine {
  debugPrintWARNINGDefault()
  engine := New() // 按照默认条件创建一个engine对象供gin server全局使用 
  engine.Use(Logger(), Recovery()) // 注册Logger和Recovery这两个中间件
  return engine //返回准备好的引擎对象
}

其中New中的实现十分的简答,就是 &Engine对象,没什么可以细究的,在New过程中我们需要关注的最主要的就是RouterGroup和trees,一个是存储的请求路径,一个是映射方法。

RouterGroup:主要存储了路由的基本信息,以及路径映射,我们实现的所有的路由都在此处。

trees:是一个methodTrees类型的slice,用于存储HTTP方法树的根节点,每个节点代表一个路由。

RouterGroup

gin中实现了所有的基础请求的接口,我们可以在routergroup.go文件中看到。

// POST is a shortcut for router.Handle("POST", path, handlers).
func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes {
  return group.handle(http.MethodPost, relativePath, handlers)
}// GET is a shortcut for router.Handle("GET", path, handlers).
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
  return group.handle(http.MethodGet, relativePath, handlers)
}

这里,我们启动阶段创建的RouterGroup就出现了,这个就是装载所有路由的地方,我们所有的路由请求都在这里完成注册。

路径注册过程页十分简单。

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

步骤如下:

  1. 计算绝对路径,这个就是请求可以到达的路径了。
  2. 把handler加入到调用链中去。
  3. 利用addRoute方法实现路由注册,其中addRouter方法是技术就是对我们之前New阶段所提到的Trees进行一个树操作,把调用链注册进去。
  4. 最后把路由返回回去,就完成了一个API的注册工作。

Run

func (engine *Engine) Run(addr ...string) (err error) {
  // 获取http服务监听路径
  address := resolveAddress(addr)
  // 开启http服务监听
  err = http.ListenAndServe(address, engine.Handler())
  return
}

Run的思路就非常简单了。

  1. 获取http服务的路径和端口。
  2. 开启服务。

其中resolveAddress中就可以看出为什么当我们什么都没有设置的时候,默认端口是8080了

func resolveAddress(addr []string) string {
  switch len(addr) {
  case 0:
    if port := os.Getenv("PORT"); port != "" {
      debugPrint("Environment variable PORT="%s"", port)
      return ":" + port
    }
    return ":8080"
  case 1:
    return addr[0]
  default:
    panic("too many parameters")
  }go
}

engine.Handler()主要是获取一个http handler对象。

func (engine *Engine) Handler() http.Handler {
  if !engine.UseH2C {
    return engine
  }
​
  h2s := &http2.Server{}
  return h2c.NewHandler(engine, h2s)
}

上述代码主要用意是判断是否是http2的服务,如果是就需要用http2的handler,如果不是就正常返回。

最后Gin Server就成功运行起来啦。

这里肯定有小伙伴要疑惑,为什么返回engine就可以了呢?

答案就是,http.handler是一个接口对象,而engine中实现了http.handler中的对象,所以我们可以将engine视为http.handler的实现类。

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  c := engine.pool.Get().(*Context)
  c.writermem.reset(w)
  c.Request = req
  c.reset()
​
  engine.handleHTTPRequest(c)
​
  engine.pool.Put(c)
}

说Go也许不直观,我们用Java的继承实现的思路打开,就可以瞬间理解了。

public interface HttpHandler {
     public void ServeHTTP(ResponseWriter, *Request);
}
​
public class Engine implements HttpHandler {
     public void ServeHTTP(ResponseWriter, *Request) {
  // do handlers
     }
}

这样是不是就好理解了,今天的笔记就到这里,明天我们继续研究gin源码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
gin-admin-api是一个基于Gin框架开发的后台管理系统的API接口。Gin框架是一个轻量级的、高性能的Go语言框架,具有路由和中间件的功能,适合用于构建Web应用程序。 gin-admin-api提供了一套完善的API接口,用于实现后台管理系统的各种功能,例如用户管理、角色管理、权限管理、菜单管理、日志管理等。通过这些接口,可以方便地进行用户的注册、登录和认证,管理用户的角色和权限,管理系统的菜单和日志信息。 gin-admin-api的优点之一是高性能。由于采用了Gin框架,它具有快速的路由匹配和中间件处理的能力,能够处理大量的请求,并在高并发的情况下保持稳定性和可靠性。 另一个优点是易于扩展和定制。gin-admin-api使用了模块化的设计,各个功能模块之间松耦合,可以根据实际需求进行灵活的扩展和定制。例如,可以根据业务需求添加新的功能模块,或者修改和优化已有的模块。 此外,gin-admin-api还提供了友好的文档和示例代码,方便开发者理解和使用。它的代码也是开的,可以在GitHub上找到,这样可以方便地进行二次开发和定制,满足特定的业务需求。 总之,gin-admin-api是一个功能丰富、高性能、易扩展的后台管理系统API接口,大大简化了后台管理系统的开发工作,帮助开发者快速构建稳定、可靠的后台管理系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值