Go-Web框架中AOP方案的实现方式

 更新时间:2023年06月05日 11:35:00   作者:今天捡到一百块钱  
本文主要介绍了Go-Web框架中AOP方案的实现方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

写在前面

最近不是在跟兔兔的七天系列嘛,目前是跟到了Web框架(好吧,这才是刚开始)。关于Web框架这一块,兔兔的文章是跟完了,也做完了,现在是在做总结。总结到AOP方案的时候,就有点蒙圈了,所以打算写下这篇文章记录总结两种AOP方案。

Gin的AOP实现方案

其实兔兔的AOP方案和Gin的AOP方案很相似。都是通过下标控制一个中间件进入到下一个中间件的。当下标大于中间件的个数的时候,整个中间件就会往回执行

image.png

特点

  • 中间件是是现在上下文中的
  • 通过下标进入下一个中间件

具体看下Gin的实现源码

image.png

具体看下兔兔的实现源码

image.png

其实是很类似的。对于这个方法,理解起来是没什么难度的。下面我就讲讲这个AOP方案的实现流程吧。

中间件注册是通过Use方法,这个方法是RouterGroup路由组提供的,在Gin中实际是抽象出了一个接口

image.png

image.png

2. 被注册的中间件是保存在路由组的属性中,上图中圈住的部分

3. 在ServerHTTP方法中匹配命中的路由视图函数符合条件的中间件

image.png

4. 将命中的视图函数添加到中间件列表中

image.png

5. 执行Next方法。每当中间件函数中有Next方法,就会再一次进入到Next方法,由于选取要执行的中间件是通过c.index控制的,每次进来都会自加1。当所有的中间件都执行完了,index的值就超过了中间件的个数。也就是退出了递归。递归最底层的方法都执行完成了,就开始一层一层返回了。

image.png

责任链制的AOP实现原理

对于责任链制的AOP方案,原理和洋葱模式是一样,(顺带提一下,Gin的设计模式叫做洋葱模式)。它的任务是一直构建"视图函数",最终构建成这样的形式

func m() {
   fmt.Println("coming middleware1...")
   func() {
      fmt.Println("coming middleware2...")
      func() {
         fmt.Println("coming middleware3...")
         func() {
            fmt.Println("coming middleware4...")
            func() {
               fmt.Println("coming middleware5...")
               func() {
               }()
               fmt.Println("outing middleware5...")
            }()
            fmt.Println("outing middleware4...")
         }()
         fmt.Println("outing middleware3...")
      }()
      fmt.Println("outing middleware2...")
   }()
   fmt.Println("outing middleware1...")
}

但是上述这种形式太不优雅了,我们就使用一个责任链的设计模式来实现、优化,但是精髓就是构建出这种样子。

image.png

注意

  • 我们需要对中间件进行一个包装,就是说对中间件的函数签名进行一个包装
  • 我们的视图函数不用变
  • 可以理解的是中间件函数就是生成一个视图函数,只不过生成的视图函数嵌入了一些别的通用逻辑
// 视图函数签名
type HandleFunc func(ctx *Context)
// 中间件函数签名
type Middleware func(next HandleFunc) HandeFunc

下文我统一将中间函数和命中的视图函数叫做中间件。不过命中的视图函数会加上特殊二字

中间件函数签名解释一下:

  • 参数next是下一次需要的中间件逻辑
  • 返回值是一个特殊的中间件,这个就是当前这个中间件的逻辑

具体的一个中间件示例代码

func Logger() Middleware {
   return func(next HandleFunc) HandleFunc {
       return func(ctx *Context){
           fmt.Println("请求来了")
           next(ctx)
           fmt.Println("请求走了")
       }
   }
}

image.png

解释示例代码:

  • Logger函数返回一个Middleware函数。返回一个视图函数构造器
  • fmt.Println("请求来了")fmt.Println("请求走了")两行代码分别嵌在next下一个需要执行的中间件逻辑

上述已经讲完了关于责任链制的AOP方法的具体原理。但是到这里还不够,这只是原理,还没有和我们的框架进行适配。接下来就具体讲讲怎么和咱们的框架进行适配。

责任链制的AOP方案应用

首先还是需要定义好视图函数、中间件函数的签名

// 视图函数签名
type HandleFunc func(ctx *Context)
// 中间件函数签名
type Middleware func(next HandleFunc) HandeFunc

我们的AOP是集成在server层面上的,在Gin中,AOP是集成在Context上下文层面上面的。其实这个没有多大的区别的,无非是设计者的设计思想而已。

说我们的AOP是集成在server层面其实还不太准确,准确来说是在路由组RouterGroup上的。

路由组RouterGroup定义一个属性保存当前组的所有中间件

image.png

2. 路由组RouterGroup提供一个方法Use注册中间件

image.png

3. 匹配路由的时候需要找出当前路由所属哪个组,并将其所有的中间件抽离出来

image.png

4. 组装中间件

在组装中间价的时候,我们需要注意:

  • 我们注册的中间件是有顺序的
  • 我们执行的中间件也是要有顺序的
  • 先注册先执行前半部分

image.png

基于上述的注意事项,我们组装的中间件应该是从后往前组装的。这里需要花点时间想想

我们可以这样想,如果是按照正向的顺序遍历middlewares的话,最后的handler应该是最后一个注册的中间件才对。这和我们的期待是完全相反的,从这也就能解释为什么我们需要从后往前组装中间件了。只有这样,最后handler才是我们第一个注册的中间件方法。

最后就执行handler方法即可。

image.png

总结

  • 基于洋葱模型的AOP方案和基于责任链制的AOP方案本质没有区别
  • Gin的AOP是集成在上下文中,我们的是集成在RouterGroup上。两种方式没有区别

 到此这篇关于Go-Web框架中AOP方案的实现方式的文章就介绍到这了,更多相关Go AOP实现内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言中实现完美错误处理实践分享

    Go语言中实现完美错误处理实践分享

    Go 语言是一门非常流行的编程语言,由于其高效的并发编程和出色的网络编程能力,越来越受到广大开发者的青睐。本文我们就来深入探讨一下Go 语言中的错误处理机制吧
    2023-04-04
  • Go语言HTTPServer开发的六种方式小结

    Go语言HTTPServer开发的六种方式小结

    Golang的Server开发显得非常简单,有很多种方式,本文就介绍了Go语言HTTPServer开发的六种方式,具有一定的参考价值,感兴趣的可以了解一下
    2021-11-11
  • golang中set数据结构的使用示例

    golang中set数据结构的使用示例

    本文主要介绍了golang中set数据结构的使用示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • 基于Golang实现Excel表格的导入导出功能

    基于Golang实现Excel表格的导入导出功能

    最近项目开发中有涉及到Excel的导入与导出功能,特别是导出表格时需要特定的格式,所以本文给大家介绍了基于Golang实现Excel表格的导入导出功能,文中通过代码示例和图文介绍的非常详细,需要的朋友可以参考下
    2023-12-12
  • GoFrame gtree树形结构的使用技巧示例

    GoFrame gtree树形结构的使用技巧示例

    这篇文章主要为大家介绍了GoFrame gtree树形结构的使用技巧示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • go mutex互斥锁使用Lock和Unlock方法占有释放资源

    go mutex互斥锁使用Lock和Unlock方法占有释放资源

    Go号称是为了高并发而生的,在高并发场景下,势必会涉及到对公共资源的竞争,当对应场景发生时,我们经常会使用 mutex 的 Lock() 和 Unlock() 方法来占有或释放资源,虽然调用简单,但 mutex 的内部却涉及挺多的,本文来好好研究一下
    2023-09-09
  • Go语言中切片使用的注意事项小结

    Go语言中切片使用的注意事项小结

    切片是引用类型,相信对大家来说都不陌生,下面这篇文章主要给大家总结介绍了关于Go语言中切片使用的一些注意事项,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2018-01-01
  • Golang实践之Error创建和处理详解

    Golang实践之Error创建和处理详解

    在 C#、Java 等语言中常常使用 try...catch的方式来捕获异常,但是在Golang 对于错误处理有不同的方式,像网上也有很多对 error 处理的最佳实践的文章,其中很多其实就是对 error 的统一封装,使用规范进行约束,本文主要是记录自己对处理 Error 的一些认识和学习
    2023-09-09
  • golang atomic原子操作示例详解

    golang atomic原子操作示例详解

    这篇文章主要为大家介绍了golang atomic原子操作示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • go第三方库sqlx操作MySQL及ORM原理

    go第三方库sqlx操作MySQL及ORM原理

    这篇文章主要为大家介绍了go第三方库sqlx操作MySQL及ORM实现原理,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05

最新评论