beego是一个组件化(模块化)的web框架,依赖于个部分的协同工作处理request,类似于php的laravel / symfony
beego组件示意图
beego执行逻辑
一个典型的web应用,入口监听到请求,然后通过路由功能映射到控制器,执行业务逻辑,最后输出响应,执行流程中通过AOP的思想在不干涉业务逻辑的同时,接入日志、缓存等。
源码分析
- beego的生命周期的几个关键节点
启动应用(app) -> 初始化上下文(context) -> 路由(route) -> 过滤器(filter, 等同于其他框架的Middleware) -> 控制器(Controller) -> 业务逻辑交互 -> 响应(response)
- 框架入口
main.go
主要是调用beego.Run()
启动框架:
func main() {
......
beego.Run()
}
beego.Run
方法,启动框架:
//====== github.com/astaxie/beego/beego.go ======
func Run(params ...string) {
//在处理http请求前完成一些初始化
initBeforeHTTPRun()
if len(params) > 0 && params[0] != "" {
strs := strings.Split(params[0], ":")
if len(strs) > 0 && strs[0] != "" {
//处理IP地址
BConfig.Listen.HTTPAddr = strs[0]
}
if len(strs) > 1 && strs[1] != "" {
//处理端口
BConfig.Listen.HTTPPort, _ = strconv.Atoi(strs[1])
}
//设置当前域名信息
BConfig.Listen.Domains = params
}
//启动应用
BeeApp.Run()
}
initBeforeHTTPRun
方法,请求开始前的初始化:
//====== github.com/astaxie/beego/beego.go ======
func initBeforeHTTPRun() {
//初始化 hook
AddAPPStartHook(
registerMime,
registerDefaultErrorHandler,
registerSession,
registerTemplate,
registerAdmin,
registerGzip,
)
......
}
回到BeeApp.Run()
方法,启动应用:
//====== github.com/astaxie/beego/app.go ======
func (app *App) Run(mws ...MiddleWare) {
addr := BConfig.Listen.HTTPAddr
......
//注册cgi服务
if BConfig.Listen.EnableFcgi {......}
//注册http server
app.Server.Handler = app.Handlers
for i := len(mws) - 1; i >= 0; i-- {
if mws[i] == nil {
continue
}
app.Server.Handler = mws[i](app.Server.Handler)
}
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")
//注册grace模块
if BConfig.Listen.Graceful {......}
//启用http配置
if BConfig.Listen.EnableHTTP {
go func() {
server := grace.NewServer(addr, app.Server.Handler)
server.Server.ReadTimeout = app.Server.ReadTimeout
server.Server.WriteTimeout = app.Server.WriteTimeout
//默认监听tcp4
if BConfig.Listen.ListenTCP4 {
server.Network = "tcp4"
}
//启动http服务
if err := server.ListenAndServe(); err != nil {
logs.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))
time.Sleep(100 * time.Microsecond)
}
//给endRunning管道发送执行成功消息
endRunning <- true
}()
}
//endRunning管道阻塞到启动成功
<-endRunning
}
在BeeApp.Run()
中将http请求注册为了app.Handlers
,让我们来看看app.Handlers
:
//====== github.com/astaxie/beego/app.go ======
import (
......
"net"
"net/http"
"net/http/fcgi"
......
)
type App struct {
//声明了处理器,指向控制器的注册
Handlers *ControllerRegister
//声明了http服务,使用net/http包
Server *http.Server
}
func init() {
BeeApp = NewApp()
}
func NewApp() *App {
//完成控制器的注册
cr := NewControllerRegister()
//创建应用实例
app := &App{Handlers: cr, Server: &http.Server{}}
return app
}
进入到NewControllerRegister
:
//====== github.com/astaxie/beego/router.go ======
//ControllerRegister结构体包含了路由注册规则,控制器处理器,过滤器(中间件)
type ControllerRegister struct {
routers map[string]*Tree
enablePolicy bool
policies map[string]*Tree
enableFilter bool
filters [FinishRouter + 1][]*FilterRouter
pool sync.Pool
}
func NewControllerRegister() *ControllerRegister {
return &ControllerRegister{
//创建新的路由树、策略树、上下文同步池
routers: make(map[string]*Tree),
policies: make(map[string]*Tree),
pool: sync.Pool{
New: func() interface{} {
return beecontext.NewContext()
},
},
}
}
至此路由注册完成
网友评论