beego源码分析(一)——初探

初探

前言

我在http.ListenAndServe相关源码简析时最后的两条总结:

1.http.HandleFunc将pattern及我们自定义的handler存储在DefaultServeMux的一个map中。

2.当http.ListenAndServe的handler为nil时,系统会从DefaultServeMux存储信息的map中匹配pattern获取对应的handler,进而处连接请求。

如果用更简单的话来总结以上两条,就是:路由的存储与匹配

beego作为一个基于golang之上的框架(此处只讨论核心http及路由部分的处理),必然脱离不了语言底层的支持。因此,我们可以大胆猜测,beego的路由处理主要是在HandleFunc的封装上,即如何更好的封装HandlerFunc且便于使用,这应该也是beego支持多种路由方式的特点了。

一、beego.Run

我们先从源码来验证一条简单的猜测,beego基于http.ListenAndServe来处理网络请求(本次仅针对http协议的处理进行分析,https协议类似)。

beego.Run()->BeeApp.Run()

// Run beego application.
func (app *App) Run() {
    ...
    app.Server.Handler = app.Handlers
    app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
    app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
    app.Server.ErrorLog = logs.GetLogger("HTTP")

    // run graceful mode
    if BConfig.Listen.Graceful {
        httpsAddr := BConfig.Listen.HTTPSAddr
        app.Server.Addr = httpsAddr
        if BConfig.Listen.EnableHTTPS {
            go func() {
                ...
                if err := server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
                    logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))
                    time.Sleep(100 * time.Microsecond)
                    endRunning <- true
                }
            }()
        }
        if BConfig.Listen.EnableHTTP {
            go func() {
                ...
                if err := server.ListenAndServe(); err != nil {
                    logs.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))
                    time.Sleep(100 * time.Microsecond)
                    endRunning <- true
                }
            }()
        }
        <-endRunning
        return
    }
    ...
}

http.ListenAndServe的源码如下:

func ListenAndServe(addr string, handler Handler) error {
    server := &Server{Addr: addr, Handler: handler}
    return server.ListenAndServe()
}

可以很明显的看出beego最终和http.ListenAndServe调用的接口是一样的。(此处只对http部分进行分析,https协议也是通用的只是调用的接口是ListenAndServeTLS)

二、Router

1.支持的路由方式

根据官网的描述,beego支持以下路由方式:

  • 基础路由
    • beego.Get
    • beego.Post
  • 自定义的 handler 实现
s := rpc.NewServer()
s.RegisterCodec(json.NewCodec(), "application/json")
s.RegisterService(new(HelloService), "")
beego.Handler("/rpc", s)
  • 固定路由&正则路由&自定义方法
// 固定路由
beego.Router("/", &controllers.MainController{})
beego.Router("/admin", &admin.UserController{})
// 正则路由
beego.Router("/api/?:id", &controllers.RController{})
beego.Router("/cms_:id([0-9]+).html", &controllers.CmsController{}))
// 指定方法
beego.Router("/api/list",&RestController{},"*:ListFood")
beego.Router("/api/create",&RestController{},"post:CreateFood")
  • 自动匹配路由
beego.AutoRouter(&controllers.ObjectController{})

-注解路由

// @router /all/:key [get]
func (this *CMSController) AllBlock() {

}

beego.Include(&CMSController{})
  • namespace
ns :=
beego.NewNamespace("/v1",
    beego.NSCond(func(ctx *context.Context) bool {
        if ctx.Input.Domain() == "api.beego.me" {
            return true
        }
        return false
    }),
    beego.NSBefore(auth),
    beego.NSGet("/notallowed", func(ctx *context.Context) {
        ctx.Output.Body([]byte("notAllowed"))
    }),
    beego.NSRouter("/version", &AdminController{}, "get:ShowAPIVersion"),
    beego.NSRouter("/changepassword", &UserController{}),
    beego.NSNamespace("/shop",
        beego.NSBefore(sentry),
        beego.NSGet("/:id", func(ctx *context.Context) {
            ctx.Output.Body([]byte("notAllowed"))
        }),
    ),
    beego.NSNamespace("/cms",
        beego.NSInclude(
            &controllers.MainController{},
            &controllers.CMSController{},
            &controllers.BlockController{},
        ),
    ),
)
//注册 namespace
beego.AddNamespace(ns)

NSNamespace/NewNamespace内部的部分存储路由时,只处理了自身的路由,总的路由还需要在NSNamespace/NewNamespace进行添加prefix,最终存储在BeeApp.Handlers.routers.
数据传输在此进行:

    app.Server.Handler = app.Handlers
    app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
    app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
    app.Server.ErrorLog = logs.GetLogger("HTTP")

在此,我们研究下几个主要入口作为示例来分析源码。

2.具体路由方式的分析

在初探中我们只做简单的功能分析,具体的分析我们在后续的文章中加以补充。

(1)beego.Get

beego.Get->BeeApp.Handlers.Get->p.AddMethod->p.addToRouter
其中p即BeeApp.Handlers,因此这一连串的操作主要是将router信息存入BeeApp.Handlers中。

(2)beego.Router

beego.Router->BeeApp.Handlers.Add->p.addWithMethodParams->p.addToRouter
与(1)同理

(3)beego.AutoRouter

beego.AutoRouter->BeeApp.Handlers.AddAuto->p.AddAutoPrefix->p.addToRouter

与(1)同理

(4)beego.Include

beego.Include->BeeApp.Handlers.Include->p.addWithMethodParams->p.addToRouter

与(1)同理

(5)beego.AddNamespace

beego.AddNamespace->BeeApp.Handlers.routers[k]

直接将namespace.handlers.routers中的添加前缀后存入BeeApp.Handlers.routers中。

AddNamespace、NSNamespace及其内部的一系列NSNamespace方法集最终依然调用n.handlers的方法集中,然后经过AddNamespace,保存至BeeApp.Handlers中

三、ServeHTTP

既然处理请求时,经过了http.ListenAndServe,根据我们对ListenAndServe的分析,最终请求会交由server.Handler的ServeHTTP来处理。beego中的Handler即为BeeApp.Handlers,其类型是ControllerRegister,也就是说请求最终交由ControllerRegister的ServeHTTP实现来处理。此处我们也是只谈下处理过程,具体的细节我们在之后的分析文章内细谈。

三、总结

我们分别从两个入口beego.Run、router两个入口的使用,可以看到beego处理的逻辑基本上和golang底层http.ListenAndServe、http.HandleFunc的原理一致,只是有更高层次的封装,以及更便利的路由声明及处理。在后续的文章中我们会对beego的处理作进一步的分析。

最后,我们可以做下几点简单的总结:

(1)routers package主要是生成路由及处理的相关信息,并保存至BeeApp.Handler中,

(2)beego.Run则是带着BeeApp.Handler的启动http的服务,

(3)接收请求后,由BeeApp.Handler的ServeHTTP进行处理,作出对应响应。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值