beego使用及源码分析一(contraller注册路由控制器与http server服务器实现)

 

本文以最简单的使用方式,来阅读beego源码,探索beego的底层实现细节,一窥其庐山真面目,

需要两部分基础,一是golang的net/http server 的基础,二是反射reflect基础,

net/http server 的基础用于了解beego的底层http服务器的实现,

reflect基础用于了解beego注册控制器和url映射调用方法后,beego底层是如何进行调用的。

一:beego使用示例

router.go文件

package routers

import (
	"my_beego_project/controllers"
	"github.com/astaxie/beego"
)

func init() {
    beego.Router("/", &controllers.MainController{},"POST:PostTest")
}

controller.go文件

package controllers

import (
	"github.com/astaxie/beego"
)

type MainController struct {
	beego.Controller
}

func (c *MainController) PostTest() {
	c.Data["Website"] = "beego.me"
	c.Data["Email"] = "[email protected]"
	c.ServeJSON()
}

main.go文件

package main

import (
	_ "my_beego_project/routers"
	"github.com/astaxie/beego"
)

func main() {
	beego.Run()
}

超级简单,没有多余的代码。

源码分析一:beego的http server

1.首先看main.go的beego.Run()

func Run(params ...string) {

	initBeforeHTTPRun()

	if len(params) > 0 && params[0] != "" {
		strs := strings.Split(params[0], ":")
		if len(strs) > 0 && strs[0] != "" {
			BConfig.Listen.HTTPAddr = strs[0]
		}
		if len(strs) > 1 && strs[1] != "" {
			BConfig.Listen.HTTPPort, _ = strconv.Atoi(strs[1])
		}

		BConfig.Listen.Domains = params
	}

	BeeApp.Run()
}

可见,此函数也很简单,解析传入的可变参数params,如果有就解析到全局配置的监听的地址和端口,以及域名

然后执行BeeApp.Run(),咱们继续看BeeApp.Run(),这里BeeApp是一个对象,Run是该对象的方法,暂时咱们先不看,继续看方法

2.BeeApp.Run()

func (app *App) Run(mws ...MiddleWare) {
    ...
    app.Server.Handler = app.Handlers

    ...
    if BConfig.Listen.EnableHTTP {
		go func() {
			app.Server.Addr = addr
			logs.Info("http server Running on http://%s", app.Server.Addr)
			if BConfig.Listen.ListenTCP4 {
				...
			} else {
				if err := app.Server.ListenAndServe(); err != nil {
					logs.Critical("ListenAndServe: ", err)
					time.Sleep(100 * time.Microsecond)
					endRunning <- true
				}
			}
		}()
	}

}

其他不是本章主线的代码,我已经注释掉了,

现在主要可观察到,http server是采用beego自定义的server,使用 app.Server.ListenAndServe() 开启服务,并且为该Server设置了监听地址

以及自定义的Handler,这个Handler是BeeApp结构体本身的,那么这个Handler是什么呢?这个BeeApp结构体又是什么?那么我们继续看代码

3.BeeApp结构

func init() {
	// create beego application
	BeeApp = NewApp()
}

// App defines beego application with a new PatternServeMux.
type App struct {
	Handlers *ControllerRegister
	Server   *http.Server
}

// NewApp returns a new beego application.
func NewApp() *App {
	cr := NewControllerRegister()
	app := &App{Handlers: cr, Server: &http.Server{}}
	return app
}

很好,BeeApp是一个App结构体的对象,这个结构体有两个成员,BeeApp是一个全局对象,通过NewApp直接在代码初始化时就分配了。

这个对象的Server在初始化时直接分配的一个空结构体,看来里面的参数应该是在后面逐个填进去的。不过这不是本章重点,

主要看看这个控制器Handlers,http server的Handler都是继承net/http包下的Handler接口,该接口有一个ServeHTTP方法,这方法才是http server的核心,

那么我们看这个Beego的Handler,主要看看这个结构的ServeHTTP方法是在干啥。

3.NewControllerRegister

type ControllerRegister struct {
	routers      map[string]*Tree
	enablePolicy bool
	policies     map[string]*Tree
	enableFilter bool
	filters      [FinishRouter + 1][]*FilterRouter
	pool         sync.Pool
}

// NewControllerRegister returns a new ControllerRegister.
func NewControllerRegister() *ControllerRegister {
	return &ControllerRegister{
		routers:  make(map[string]*Tree),
		policies: make(map[string]*Tree),
		pool: sync.Pool{
			New: func() interface{} {
				return beecontext.NewContext()
			},
		},
	}
}

可见,该函数主要就是构建一个ControllerRegister 对象,该对象有几个成员,全都不对外开放,其中有个routers,重点关注,可能就是跟我们注册控制器,

beego服务器 根据url映射到具体方法的功能有关。

不过现在我们看看ControllerRegister结构的ServeHTTP方法,看看具体怎么处理http请求。在哪里做的路由

看代码:

func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) {

    ...
    routerInfo, findRouter = p.FindRouter(context)
    ...
    if routerInfo.routerType == routerTypeRESTFul {
        ...
    }else if routerInfo.routerType == routerTypeHandler {
        ...
    }else {
        runMethod = method
    }

    ...
    vc := reflect.ValueOf(execController)
	method := vc.MethodByName(runMethod)
	in := param.ConvertParams(methodParams, method.Type(), context)
	out := method.Call(in)
    ...

}

同样,省略掉了无关代码,可以看到,ControllerRegister作为自定义的Handler,所有http请求都将经过ServeHTTP方法,在里面进行路由,调用对应的方法进行逻辑处理。

这里通过反射的方式调用到具体的方法。那么这里竟然还有参数传递进去,参数是啥呢?经过我的源码追踪,发现是Nil。也就是不会存在参数,那就奇怪了。

 

源码分析二:controller注册器注册路由

func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {
	BeeApp.Handlers.Add(rootpath, c, mappingMethods...)
	return BeeApp
}

继续

 

你可能感兴趣的:(MyBeego,beego,http,server)