美文网首页
懂了,中间件是这样实现的

懂了,中间件是这样实现的

作者: mick_ | 来源:发表于2019-12-05 12:31 被阅读0次

做web开发都会用到中间件,大家对中间件有多少了解呢?
近期在使用goland的轻量级框架gin,研究了其中的中间件的源码,受此启发实现一个简单的中间件。

达到的效果

递归调用,使用logger中 ,调用recovery,调用业务函数


逻辑.png

创建一个结构体与中间件的函数类型

// 中间件的函数类型
type HandleFunc func(*Request)
// 执行函数的结构体重点
type Request struct {
    index      int    `desc:"索引控制中间件的"`
    middleware []HandleFunc     `desc:"存放所有的中间件"`
}

将中间件添加到结构体

// @title    添加中间件
// @description   将需要添加的中间件添加到执行切片中
// @param     middlewares        ...HandleFunc         "符合中间件的类型"
func (r *Request) Register(middlewares ...HandleFunc) {
    r.middleware = append(r.middleware, middlewares...)
}

执行函数

// @title    执行中间件
// @description   回掉执行所有的中间件
func (r *Request) Next() {
    // TODO 将索引数自增
    r.index++
    // TODO  检测索引是否超过中间件的数量
    if r.index >= len(r.middleware) {
        return
    }
    // TODO 执行下一个中间件
    r.middleware[r.index](r)
}

这里着重讲解下request.index字段的用处。
中间件模式是递归的,不是组合方式,这是与插件模式的重要区别。
第一个中间件函数的实现中,需要递归的调用request.Next唤起下一个中间件函数,如此不断的递归向后,直到request.index到达request.middlewares的末尾,则递归终止。

递归的好处就是靠前的中间件是包裹着靠后的中间件的,这种自顶向下的结构可以实现非常灵活的框架设计。

执行我们的中间件

// @title    log中间件
// @description   记录执行顺序
// @param     r        *Request         "请求结构体"
func logger(r *Request) {
    fmt.Println("我是第一个中间件,开始")
    // TODO 执行下一个中间件 执行完毕后返回执行下一个
    r.Next()
    fmt.Println("执行结束")
}
// @title    恢复中间件
// @description   获取panic防止程序崩溃
// @param     r        *Request         "请求结构体"
func recovery(r *Request) {
    defer func() {
        if err := recover(); err != nil {
            log.Println("出错了")
        }
    }()

    r.Next()
}
func main() {
    r := NewRequest()
    // TODO 注册函数
    r.Register(logger,recovery)
    r.Next()
}

总结

上面我们自己手写了一个中间件模式,大体的流程如上,

  • 主要是要明白index的作用,他是控制我们中间件的执行顺序
  • Gegister函数是用于添加我们的中间件函数,顺序与添加的顺序一致
  • Next是出发我们的下一个中间件的函数,同时会把index自增
    这块的设计还是很巧妙,可细细品味

相关文章

网友评论

      本文标题:懂了,中间件是这样实现的

      本文链接:https://www.haomeiwen.com/subject/scddgctx.html