1. 仓库顶层结构
Go
beego/ module github.com/beego/beego/v2 (go 1.24.2)
├── server/web/ # Web 框架(最大的模块)
│ ├── context/ # Context/Input/Output
│ ├── session/ # 会话(12 种引擎)
│ ├── grace/ # 平滑重启(fd 继承)
│ ├── filter/ policy等 # 扩展过滤器
│ ├── captcha/ swagger/ pagination/ ...
│ └── *.go # server/router/tree/controller/filter/namespace...
├── client/
│ ├── orm/ # ORM(含 internal/models 元数据)
│ │ ├── clauses/ hints/ filter/ migration/ mock/
│ │ └── orm.go orm_queryset.go db.go db_alias.go db_*.go...
│ ├── httplib/ # HTTP 客户端
│ └── cache/ # 缓存 + 缓存模式
├── core/
│ ├── config/ (+json/yaml/toml/xml/ini/env/etcd)
│ ├── logs/ # 日志(适配器模式典范)
│ ├── utils/ validation/ berror/ admin/ bean/
├── task/ # cron 调度
└── test/ # 集成测试
依赖方向(core 不依赖上层的库):
Go
server/web ──────────────┐
client/orm ──────────────┤
client/httplib ──────────┼──→ core/*(config/logs/utils/berror...)
client/cache ────────────┤
task ────────────────────┘
core 是无 Web 依赖的"工具带"------这就是"只用日志不引服务器"可行的原因。
2. server/web 文件地图(核心 14 个文件)
|--------------------------|--------|-----------------|--------------------------------------------------------|
| 文件 | 行数级 | 职责 | 关键符号 |
| beego.go | 小 | 全局入口/钩子 | BeeApp、Run()、AddAPPStartHook、initBeforeHTTPRun |
| server.go | 大 | HttpServer 生命周期 | HttpServer、NewHttpSever、Run、路由代理方法 |
| router.go | 最大 | 注册+分发 | ControllerRegister、ControllerInfo、serveHttp |
| tree.go | 中 | 路由树 | Tree、leafInfo、addseg、match、splitSegment |
| controller.go | 中 | 控制器基类 | Controller、ControllerInterface |
| filter.go | 小 | 过滤器 | FilterChain、FilterRouter |
| policy.go | 小 | 策略 | PolicyFunc、execPolicy |
| namespace.go | 中 | 命名空间 DSL | Namespace、LinkNamespace、NS* |
| config.go | 大 | 配置定义+加载 | BConfig、Config、newBConfig |
| hooks.go | 小 | 默认启动钩子 | registerMime/Session/Template/Admin/Gzip |
| error.go | 中 | 错误处理 | ErrorMaps、ErrorHandler、exception |
| flash.go | 小 | Flash | FlashData |
| admin.go / statistics.go | 中 | 监控统计 | FilterMonitorFunc、StatisticsMap |
| staticfile.go fs.go | 中 | 静态文件 | serverStaticRouter、LRU 缓存 |
3. 贯穿全库的三大设计模式
3.1 注册表模式(Registry)
beego 每个可扩展点都是"名字 → 构造函数"的 map + Register:
|------------|------------------------------------------------|----------------------|
| 模块 | 注册表 | 注册时机 |
| logs | adapters map[string]newLoggerFunc(log.go:91) | 各适配器 init() |
| config | adapters map[string]Config(config.go:205) | 各格式包 init() |
| session | provides map[string]Provider(session.go) | 各引擎 init() |
| cache | adapters map[string]Instance(cache.go:78) | 各适配器 init() |
| admin 命令 | commandRegistry(command.go) | 各模块 registerCommands |
| berror | defaultCodeRegistry(codes.go:30) | DefineCode 调用 |
| validation | funcs map[string]reflect.Value(util.go) | init 反射收集 |
读懂这一模式,新增任何自定义引擎/适配器的路径都一致:实现接口 → init() 里 Register → 配置字符串切换。
3.2 洋葱过滤器链(FilterChain)
三个模块不约而同使用同一形态:
Go
type FilterChain func(next Filter) Filter
// web: func(*context.Context) (server/web/filter.go:26)
// orm: func(ctx, *Invocation) []interface{} (client/orm/filter.go:23)
// httplib: func(ctx, *BeegoHTTPRequest) (*http.Response, error)
装配方式都是"倒序折叠":注册早的在最外层。S07 详析 web 的实现。
3.3 模板方法(Base + 注入)
core/config 的 BaseConfiger(config.go:88)只持有一个 reader func(key),类型转换(Int/Bool/Strings/Default*)全部在基类实现;ini/etcd 只提供 reader。这是"接口+嵌入复用"的 Go 风格模板方法。
4. 全局单例盘点
|-----------------------------------|--------------------|-----------------------------|
| 全局变量 | 位置 | 初始化 |
| BeeApp *HttpServer | server.go:42 | 包 init |
| BConfig *Config | config.go:442 | 包 init(读 conf/app.conf) |
| GlobalSessions *session.Manager | hooks.go 注册时 | Run 时 |
| BeeTemplates | template.go | Run 时 |
| ErrorMaps | error.go | registerDefaultErrorHandler |
| globalTaskManager | task.go:830 | 包 init |
| beeLogger *BeeLogger | logs/log.go:650 | 包 init |
| defaultModelCache | orm/models_boot.go | 包 init |
| dataBaseCache | orm/db_alias.go:58 | 包 init |
Go 包 init 的执行顺序决定了:import 即初始化,这解释了为什么"改配置必须在 Run 之前"。
5. 一次请求的模块协作(全景图)
Go
HTTP 请求
│
▼
http.Server(标准库)────────────────────────────┐
│ │ HttpServer.Run 组装:
▼ │ Handler=ControllerRegister.ServeHTTP
ControllerRegister.ServeHTTP (router.go:995) │ + 中间件包裹 + 超时设置
│ GetContext: sync.Pool 取 Context │
▼ │
chainRoot.filter(洋葱链,最内层=serveHttp) │
│ │
▼ │
serveHttp (router.go:1005) │
├─ RecoverFunc(defer) │
├─ BeforeStatic 过滤器 → 静态文件 │
├─ body 解析 / Session 初始化 ──────────────┤ session.Manager(core 独立模块)
├─ BeforeRouter 过滤器 │
├─ FindRouter: Tree.Match │
├─ BeforeExec 过滤器 + policy │
├─ 控制器 Init→Prepare→XSRF→Get/Post→Render→Finish
├─ AfterExec / FinishRouter 过滤器 │
└─ LogAccess + StatisticsMap(QPS) │
│
期间使用:core/logs、core/config(BConfig)、 │
client/orm(业务层注入)... ┘
后续各篇分别放大每个环节。
6. 测试组织
- 各包
*_test.go单元测试(tree_test/router_test 覆盖极全,是学习算法的第二手资料)
test/目录:集成测试(真实起服务跑 case)
core/config/base_config_test.go:共享测试套件,被 6 个格式复用------接口一致性测试的好范例
scripts/:CI 脚本;sonar-project.properties:静态扫描
7. 依赖库选型(值得抄的作业)
|---------------------------------|----------------------|
| 库 | 用途 |
| mitchellh/mapstructure | 配置→结构体(全部 config 实现) |
| redigo / go-redis | redis(session/cache) |
| hashicorp/golang-lru | ORM stmt 缓存、静态文件缓存 |
| opentracing / otel / prometheus | 可观测三件套(filter 目录) |
| gomemcache / gossdb / ledisdb | cache 多引擎 |
| shiena/ansicolor | Windows 彩色日志 |
8. 源码阅读路线
- 跟一个请求:beego.go → server.go Run → router.go ServeHTTP/serveHttp → tree.go Match → controller.go
- 跟一次配置:config.go init → parseConfig → assignConfig → beegoAppConfig
- 跟一条日志:logs 包级函数 → writeMsg → 适配器 WriteMsg → file.go doRotate
- 跟一条 SQL:NewOrm → QuerySeter → db.go ReadBatch → db_tables getJoinSQL