beego.run() 启动时执行三步:初始化全局模块(config、logs等)、注册路由处理器app.handlers(即controllerhandler)、最后调用http.listenandserve;其中controllerhandler负责路径匹配、context注入与控制器方法执行。

Beego 的核心源码不是靠“读完”理解的,而是靠定位关键模块、看清调用链路、验证行为边界来掌握的 —— 它的架构本质是“模块注册 + 中间件式拦截 + MVC 路由分发”,不是单体黑盒。
beego.Run() 启动时到底做了什么
很多人以为 beego.Run() 就是启动 HTTP 服务,其实它干了三件事:初始化全局模块(config、logs、cache)、注册默认路由处理器(app.Handlers)、最后才调用 http.ListenAndServe。关键点在于:app.Handlers 不是原生 http.Handler,而是 beego 自己实现的 ControllerHandler,它会先解析请求路径、匹配路由表、注入 context.Context 和 beego.Controller 实例,再执行用户控制器方法。
常见误区是直接替换 http.DefaultServeMux 或自己 wrap http.Handler,这会导致 beego 的中间件(如 BeforeRouter)、Session、参数绑定等功能全部失效。
- 不要在
main.go里手动调用http.ListenAndServe,否则绕过 beego 生命周期 -
beego.BConfig的配置项(如Listen.HTTPPort)只在beego.Run()内部生效,提前修改无效 - 如果你看到请求没进控制器,先检查
beego.Router是否在init()中执行,且包导入用了_ "yourproject/routers"形式
路由注册机制:beego.Router 和 GlobalControllerRouter 的区别
beego.Router 是面向开发者的便捷封装,最终把路由规则写入全局变量 beego.GlobalControllerRouter(类型为 map[string][]*ControllerInfo)。但注意:这个 map 只存“路径 → 控制器方法列表”的映射,不包含中间件、过滤器或参数校验逻辑 —— 这些是在 ControllerInfo 结构体里单独维护的。
真正决定请求能否走到某个方法的,是 ControllerHandler.ServeHTTP 中的三步匹配:路径前缀匹配 → HTTP 方法检查 → AllowHTTPMethods 白名单校验。如果路由写了 "get:List;post:Create",但请求是 PUT,就会 405,不会 fallback 到其他方法。
-
beego.Router("/api/:id", &controllers.UserController{}, "get:Get;delete:Delete")中的"get:Get"是字符串解析,不是反射调用,拼错大小写或方法不存在会 panic -
GlobalControllerRouter是包级变量,多模块并发注册时无锁,不建议在运行时动态增删(比如热加载路由) - RESTful 风格路由(如
beego.RESTRouter)底层仍是同套匹配逻辑,只是自动补全了 CRUD 对应的 method 映射
Controller 执行生命周期中哪些环节可干预
一个请求从进入 ControllerHandler 到返回响应,会依次经过:Prepare → method handler → Finish。其中 Prepare 是最常被忽略的钩子 —— 它在路由匹配成功后、具体方法执行前调用,适合做权限校验、上下文初始化、请求日志打点。
但要注意:Prepare 不是中间件。它属于控制器实例方法,每个控制器可重写;而真正的中间件(如 InsertFilter)作用于整个应用或某段路径前缀,优先级更高、更早触发。
- 在
Prepare里调用c.Abort()会跳过后续方法,但不会触发Finish;想确保清理逻辑执行,得手动加 defer 或统一用Finish -
c.Data["json"] = xxx+c.ServeJSON()是常用响应方式,但底层会调用json.Marshal,若结构体字段没加json:tag 或含循环引用,会直接 500 - 控制器方法签名必须是
func(*YourController),不能带额外参数,beego 不支持依赖注入
ORM 模块为什么能脱离 HTTP 独立使用
因为 beego/orm 是完全解耦的设计:它只依赖 database/sql 和驱动,不引用任何 beego HTTP 相关代码。你在非 Web 项目(如定时任务、CLI 工具)里 import "github.com/astaxie/beego/orm" 完全可行,只要手动调用 orm.RegisterDriver 和 orm.RegisterDataBase 即可。
但要注意:模型 struct 的 orm: tag 解析、自动建表(SyncDatabase)、事务控制这些功能,和 beego 的 Controller 生命周期无关 —— 它们是纯 ORM 层行为。很多人误以为要用 beego 就必须跑完整 MVC,其实大可只取其 ORM 或 cache 模块。
-
orm.Debug = true会把 SQL 日志输出到logs模块,但若没初始化logs,日志就丢了 —— 建议显式调用logs.SetLogger -
orm.NewOrm()返回的是线程安全的实例,但QuerySeter(如o.QueryTable("user"))不是,不能跨 goroutine 复用 - 模型定义里用
type User struct { ID int `orm:"auto"` },这个"auto"是 beego/orm 特有语法,换其他 ORM 就不兼容
真正卡住人的从来不是源码有多深,而是搞不清哪个模块负责哪段流程、哪个配置只在哪个阶段生效、以及哪些“约定”其实是硬编码逻辑(比如 routers/init.go 必须用 init() 函数注册)。读源码之前,先跑通一个最小路由 + 控制器 + ORM 查询链路,比通读 beego/app.go 有用得多。











