一、热加载go get github.com/pilu/fresh快速编译,省去了每次手动go run二、gin特点轻量级、运行速度快,性能、高效擅长API接口的高并发,项目规模不大,业务简单三、Engine启动器Engine是框架的实例,使用NEW()或着Default()来创建。使用gin实际上就是使用engine的方法。其中engine.trees    !!!负责存储路由和handle方法的映射,采用类似前缀树的结构RouterGroup     是一个结构,其中的Handlers存储着所有中间件type Engine struct {RouterGroup         ####...trees            methodTrees        ####...}四、Run· Run:连接路由到http。服务器开启监听和服务HTTP请求。这是http.ListenAndServe(Addr,engine)ListenAndServe监听TCP网络地址addr,然后用engine调用Serve来处理传入连接上的请求。ListenAndServe:监听TCP网络地址addr,然后调用带有handler的server来处理传入连接的请求。handler是一个带有ServeHTTP的方法的接口ServeHTTP:请求到达后,调用接口。创建上下文对象-->初始化上下文对象-->处理请求-->回收上下文对象处理请求是用的 engine.heandleHTTPRequest方法:(redix树就是engine结构中的一个前缀树,可以快速找到请求处理方法)获取请求方式对应的radix树-->得到请求路径匹配的radix树节点,将节点的路由处理器填充到上下文context-->执行上下文context的next方法处理请求-->如果请求没有匹配到或者请求方法不循序,响应对应错误可以看到engine本质上是路由处理器,内部定义了路由处理的各种规则,底层还是go的net/http包。五、gin.Context.Next()gin.Context 上下文对象,负责处理 请求和回应 ,其中handlers是存储处理请求时中间件的处理方法利用engine.pool.New创建gin.context对象,内部采用sync.pool减少gin.context实例化带来的内存消耗。Next()方法实际上是逐个调用处理器的请求,而中间件也是处理器类型,所以也可以通过c.Next()来工作。用c.index找到对应的处理器next再中间件内部使用,它执行调用处理程序内部链中挂起处理程序。next内部逻辑:1.指向要执行的中间件。初始值是-1.2.遍历所有的处理器,依次调用用它们来处理请求gin.context的终止:调用gin.context.abort()方法直接把index指到63,也就是路由处理的器的最大数量,实现终止处理器调用的功能。六、中间件  通过routergroup.use来注册中间键因为engine中也集成了routergroup,所以可以使用engine.use()注册中间件。use():往RouterGroup.hanlers中追加写入中间件。这说明了会按照添加顺序进行执行。func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {group.Handlers = append(group.Handlers, middleware...)return group.returnObj()}· 注册中间件:gin高性能主要依靠engine.tree,每一个节点的内容类似于一个key-value的字典树,value是一个[]handlerFunc;里面存储的是按顺序执行的中间件和handle控制器方法!!!· 注册全局中间件:engine.use():调用RouterGroup.Use()往RouterGroup.Handlers中写入记录。使用一个全局中间件连接到路由,通过use()附加的中间件包含在每一个请求的处理程序链中。即使是404、405、静态文件....· 注册路由组中间件:通过Group()方法返回一个RouterGroup。返回的routerGroup是engine的routergroup的模板,可以节省填写路径和中间件用 group.use() 写入分组七、Default· Default:返回一个已经附加Logger和Recovery中间件的Engine实例。engine := New()engine.Use(Logger(), Recovery())可以看到default就是调用了gin.New(),添加了Logger和Recovery中间件Logger:日志写入的中间件Recovery:错误处理,遇到panics时按照设置的handle方法处理· gin.New()直接使用gin.New()是初始化一个干净的engine对象逻辑:1. 初始化一个engine对象2. 设置sync.poold的新建context对象函数· 初始化engine:1. routerGroup:设置了根路径2. RedirectTrailingSlash:自动把/foo/重定向到/foo,即可以多打一个斜杠RedirectFixedPath:是否允许再找不到目标路径时,将/FOO和/../foo这种错误路径自动修复HandleMethodNotAllowed:是否自动适配请求方式,如用post方法请求get,是否自动转用get请求3. trees 创建容量为9的redix树切片,对应9种请求方法func New() *Engine {debugPrintWARNINGNew()engine := &Engine{RouterGroup: RouterGroup{Handlers: nil,basePath: "/",      root:     true,     # 为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"},trustedCIDRs:           defaultTrustedCIDRs,}engine.RouterGroup.engine = engineengine.pool.New = func() interface{} {return engine.allocateContext()}return engine}八、Groupgroup := e.Group("/imgroup")创建一个路由分组func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {return &RouterGroup{Handlers: group.combineHandlers(handlers),      #继承父handlers的同时加上新传入handlerbasePath: group.calculateAbsolutePath(relativePath),    ##设置路径engine:   group.engine,     #所属engine}}combineHandlers:判断handlers数量是否超出最大62,把engine的handles深拷贝copy下来,把传入的handles也copy下来,然后返回被copy初始化的handlers九、注册路由RouterGroup.get()注册一个get路由func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {return group.handle(http.MethodGet, relativePath, handlers)}可以发现get()方法其实就是调用了一个group.handlegroup.handle():处理注册一个新的请求句柄和中间件与给定的路径和方法。  1. 把传入的路由地址转码2. 将handle添加到handles3. group.engine.addRoute(httpMethod, absolutePath, handlers)addRoute:1.根据相对路径和routergroup路径计算绝对路径2.添加路由,(radix树添加在最后)十、gin.context:gin的context和go的原生context不是一回事gin上下文方法分为几个大类:创建、流程控制、错误控制、元数据管理、请求数据、响应渲染、内容协商方法按照分类gin.context.copy():copy返回上下文的副本。拷贝上下文传递给goroutine时,必须使用此选项。防止被回收ctx.Query()获取url的请求key-value参数ctx.PostForm()获取post值key-valuectx.ShouldBindWith()监听绑定ctx.HTML()渲染成htmlctx.Param()获取restful这种的参数   /user/:userid十一、注意点1. context的创建时,使用sync.pool来复用内存。2. gin底层是net/http包,gin的本质是以恶搞路由处理器3. 每个请求方法都有一颗radix树(get/post...)4. 添加中间件的过程就是切片追加元素的过程,也决定了中间件会按照添加时间顺序来执行5. 可以为不同路由组添加不同的中间件6. 路由组本质就是一个模板,维护了路径前缀、上级路由中间件等信息,让用户省去了重复配置相同前缀和中间件的操作7. 新路由组集成父路由组的所有处理器8. 如果context需要被并发使用,需要使用context副本,拷贝context需要使用gin.copy()来使用9. 拷贝上下文必须使用gin.context.copy()十二、总结1. gin框架路由原理:gin是一个高性能路由分发器,负责将不同方法的多个路径注册到各个handle函数;当收到请求时,负责快速查找请求的路径是否有对应的处理函数,并且进行下一步业务逻辑处理。通过redix tree来进行高效的路径查询,gin对每一种http方法都生成一颗radix树2. 注册路由:    router.get("/hello",func (*gin.context))RouterGroup.Get/POST...都是对routergroup.handle的调用,只是传入的httpMethod不同;httpMethod将传入的相对路径通过和router的路径计算得到了绝对路径;将传入的handel合并到router的handels切片,因为是追加添加,所以是顺序进行的,前面是router之前use的中间件;调用addRouter方法调用gin.tree.node.addrouter()添加路由通过method找到对应的radix树,在对应的radix树中插入了path-handle的key-value值,方便快速查找3. 路由的匹配   engine.run(addr string)Gin内部实际上是调用了Go自带库的net/http库中的ListenAndServe函数,http.ListenAndServe(addr, handler)的handler是engine自带实现了的,在gin中调用ListenAndServe也是传入的engine;gin.Handler中实现了ServeHTTP方法;首先从engine的对象池中pool获取一个上下文对象并对其的属性进行重置;然后将context重新放回engine的context池中;然后以该context调用handleHTTPRequest再通过getvalue找到路由对请求进行处理,最后再把context放入engine中。十三、总结精简服务启动:  main.go、获取engine对象、注册路由、启动服务、http.ListenAndServe()路由注册:RouterGroup.GET/POST..、RG.handle()、RG.addrouter、tree.addrouter请求处理:engine.run、http.ListenAndServe、engine.ServeHTTP、engine.pool.get、engine.handleHTTPRequest、c.next执行、engine.pool.put十四、Tarix挖个坑,暂时还没了解gin中radix的具体实现。

Golang源码学习----gin框架简单阅读相关推荐

  1. Golang源码学习(二)----Go源码学习基础

    ### 本文源码版本为 GO 1.17.8 Windows/amd64: ### 可能参与对比的版本:GO 1.16.2 Linux/amd64一.Golang的编译器究竟是如何工作的? (学习源码有 ...

  2. iOS源码学习总结框架

    1.ARChromeActivity: 用于在Google Chrome中打开网址的UIActivity子类. 2.KINWebBrowser: 它使用iOS 8的 WKWebView API编写,同 ...

  3. 结合redis设计与实现的redis源码学习-2-SDS(简单动态字符串)

    上一次我们学习了redis的内存分配方式,今天我们来学习redis最基本的数据结构SDS,在redis的数据库里,包含字符产值的简直对在底层都是由SDS实现的. SDS的基本数据结构是sdshdr结构 ...

  4. ThinkPHP5.0源码学习之框架启动流程

    ThinkPHP5框架的启动流程图如下: ThinkPHP5的启动流程按照文件分为三步: 1.请求入口(public/index.php) 2.框架启动(thinkphp/start.php) 3.应 ...

  5. Greenplum数据库源码学习——BackgroundWorker框架

    BackgroundWorker框架 在Postmaster.c有用于存放BackgroundWorker类型进程信息的结构体PMAuxProcList,其中包含的进程有:ftsprobe proce ...

  6. Go框架 gin 源码学习--路由的实现原理剖析

    往期回顾: gin源码解析 - gin 与 net/http 的关系 gin 源码解析 - 详解http请求在gin中的流转过程 上面两篇文章基本讲清楚了 Web Server 如何接收客户端请求,以 ...

  7. MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)(转)

    阅读目录 一.MVC原理解析 1.MVC原理 二.HttpHandler 1.HttpHandler.IHttpHandler.MvcHandler的说明 2.IHttpHandler解析 3.Mvc ...

  8. MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)

    前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎.这两天算是理解了一小部分,这里先记录下来,也给需要的园友一个参考,奈何博主技术有限,如有理解不妥之 ...

  9. Java并发包源码学习之AQS框架(三)LockSupport和interrupt

    接着上一篇文章今天我们来介绍下LockSupport和Java中线程的中断(interrupt). 其实除了LockSupport,Java之初就有Object对象的wait和notify方法可以实现 ...

最新文章

  1. xshell使用xftp传输文件、使用pure-ftpd搭建ftp服务
  2. ajax无刷新留言板远吗,基于jquery实现ajax无刷新评论
  3. nyoj 61(双线程dp)
  4. [Python图像处理] 十二.图像几何变换之图像仿射变换、图像透视变换和图像校正
  5. 权限操作-springSecurity快速入门-使用自定义页面
  6. fn映射 mac 键盘_【新鲜评测】高颜值、低延迟、多模式跨平台办公神器-米物蓝牙键盘...
  7. Andrew Ng机器学习公开课笔记 -- Logistic Regression
  8. 开发日记:接口开发设计
  9. 给我一个BigGAN,我就能开一家美术作品店,一幅画卖200美元
  10. 电商后台管理系统项目总结(一)
  11. Word界面中无法切换到输入法的解决…
  12. 怎么知道服务器是否正版,盗版太坑爹!五招识别Win7旗舰版正版
  13. python量化投资系统构建_零基础搭建量化投资系统 以Python为工具
  14. 在Kali操作系统上使用metasploit
  15. Android仿手机淘宝多级下拉菜单
  16. python 笛卡尔_Python实现求笛卡尔乘积的方法
  17. dizcuz手机API-mobile
  18. 详谈京东的商品搜索系统架构设计
  19. matlab逐步回归结果分析,matlab中的逐步回归.doc
  20. (*p)[3]的理解

热门文章

  1. 跳出任务管理的泥沼,拥抱甘特图的怀抱
  2. 点云数据类型分析 sensor_msgs/PointCloud2
  3. 中华英才网走到这个地步,失败,技术哪去了?
  4. 最新 Flink 1.13 时间和窗口(时间语义、Watermark、Window 窗口、Trigger)快速入门、详细教程
  5. 身为在软件测试摸爬滚打多年工程师的感悟,写给正在迷茫的你!
  6. cmwap和cmnet接入点的区别
  7. Echarts3-- 向echarts图表里传入数据
  8. 前端WEB开发面试题整理
  9. 企业微信内容如何值入广告?
  10. python的序列类型