Driver Manager
Driver Manager
pkg/driver/ 提供一个泛型驱动管理器 Manager[T],用于在运行时按名称选择某种基础设施的具体实现。所有"可插拔"的能力(数据库、日志、缓存、Redis、静态资源)都基于这个 Manager 实现。
为什么需要 Driver Manager
考虑数据库这一场景:同一个项目可能在不同环境下使用 MySQL 或 PostgreSQL,测试时希望使用 SQLite,本地试用时希望使用纯内存。如果在代码中硬编码具体驱动,每次都要修改源码;如果直接通过 if/else 切换,扩展新驱动会污染原有代码。
Driver Manager 把"注册驱动"与"使用驱动"解耦:
- 驱动通过
Extend(name, factory)注册到 Manager - 使用方通过
Make(name, config)按名字获取实例 - 配置文件中只需要写
database.driver: "mysql"即可切换实现
Manager[T] API
type DriverFactory[T any] func(config any) (T, error)
type Manager[T any] struct { /* ... */ }
func NewManager[T any]() *Manager[T]
// 注册一个驱动
func (m *Manager[T]) Extend(name string, factory DriverFactory[T])
// 设置默认驱动名
func (m *Manager[T]) SetDefault(name string)
// 按名称创建驱动实例
func (m *Manager[T]) Make(name string, config any) (T, error)
// 使用默认名称创建
func (m *Manager[T]) MakeDefault(config any) (T, error)
// 检查驱动是否已注册
func (m *Manager[T]) Has(name string) bool内置 Manager 与可用驱动
每个领域都有自己的 Manager,定义在 pkg/server/<domain>/driver/manager.go:
| 领域 | Manager | 可用驱动 |
|---|---|---|
| 数据库 | database/driver/manager.go |
mysql、postgresql、sqlite、memory |
| 日志 | logger/driver/manager.go |
development、production |
| 缓存 | cache/driver/manager.go |
redis、memory、none |
| Redis | redis/driver/manager.go |
redis |
| 静态资源 | http_server/static/driver/manager.go |
embed、disk |
数据库驱动
| 驱动名 | 用途 | 备注 |
|---|---|---|
mysql |
MySQL / MariaDB | 推荐生产使用 |
postgresql |
PostgreSQL | |
sqlite |
文件型 SQLite | 适合单机部署 |
memory |
纯内存(不持久化) | 适合 Demo / 单元测试,不支持 goose 迁移 |
日志驱动
| 驱动名 | 用途 |
|---|---|
development |
彩色控制台输出,带调用栈,开发期使用 |
production |
JSON 格式,适合接入 ELK / Loki |
缓存驱动
| 驱动名 | 用途 |
|---|---|
redis |
基于 Redis 的缓存,共享多实例 |
memory |
进程内缓存,无需依赖 Redis |
none |
禁用缓存,所有 Get 返回 miss |
切换驱动
切换驱动通常不需要写代码,只需修改 config.yaml 或环境变量:
database:
driver: "postgresql"
host: "10.0.0.1"
port: 5432
cache:
driver: "memory"或:
export DATABASE_DRIVER=postgresql
export CACHE_DRIVER=memory下一次启动时,对应的 Assembly 会从配置中读取 *.driver 字段,通过 manager.Make(name, cfg) 创建实例,并注册到容器中。
扩展自定义驱动
假设你需要为数据库新增一个 ClickHouse 驱动:
package myapp
import (
"cnb.cool/mliev/open/go-web/pkg/server/database/driver"
"gorm.io/gorm"
chdriver "gorm.io/driver/clickhouse"
)
func init() {
driver.Manager().Extend("clickhouse", func(config any) (*gorm.DB, error) {
cfg := config.(driver.Config)
dsn := buildDSN(cfg)
return gorm.Open(chdriver.Open(dsn), &gorm.Config{})
})
}随后在配置文件中切换:
database:
driver: "clickhouse"
host: "..."关键:扩展驱动建议在你的 应用项目 中通过
init()完成,而不是改pkg/server/database/driver/。这样你的项目升级go-web框架时不会有合并冲突。
静态资源驱动
http_server 启动时根据 http.static_mode 决定如何挂载静态文件:
embed—— 使用cmd.WithWebStaticFs注入的embed.FS,适合编译后单二进制部署disk—— 使用http.static_dir列表中的本地路径,适合开发期热修改
切换方式:
http:
load_static: true
static_mode: "disk"
static_dir:
- "./static"
- "./public"同时支持多个实现的优势
由于 Manager 是按名称索引的,你可以在不删除旧驱动的前提下并存多个实现,然后通过配置切换:
- 灰度迁移:先把新驱动跑在测试环境,生产仍使用旧驱动
- A/B 测试:不同实例使用不同驱动,对比性能
- 紧急回滚:新驱动出问题时只需修改一行配置 + 重启