声明式配置
xOption 函数式选项模式,声明式装配缓存、数据库和路由
xOption — 声明式配置
xOption 基于函数式选项模式,让业务侧以声明式风格选择框架内置组件(缓存后端、数据库驱动、路由挂载),而非手工编写初始化节点。Register 在启动时根据 Config 自动完成装配。
import (
xOption "github.com/bamboo-services/bamboo-base-go/major/option"
xOptCache "github.com/bamboo-services/bamboo-base-go/major/option/cache"
xOptDatabase "github.com/bamboo-services/bamboo-base-go/major/option/database"
// v1.2.0 起数据库驱动插件化:按需空白导入对应驱动插件触发注册
_ "github.com/bamboo-services/bamboo-base-go/plugins/database/mysql" // 仅用 MySQL 时
_ "github.com/bamboo-services/bamboo-base-go/plugins/database/postgres" // 仅用 PostgreSQL 时
)设计理念
传统的 xRegNode.RegNodeList 要求业务侧编写完整的初始化工厂函数(打开连接、拼装 DSN、注册中间件)。对于框架内置组件(缓存、数据库、路由),xOption 将这部分逻辑内化到框架层,业务侧只需描述「选哪种 + 用什么参数」。
v1.2.0 数据库驱动插件化:框架不再内置任何 GORM 驱动。驱动枚举与 Dialector 工厂注册表下沉至
common/database(xDB),五种内置驱动(MySQL / PostgreSQL / SQLite / Oracle / SQL Server)拆分为独立插件plugins/database/*。业务侧需 空白导入对应驱动插件 触发注册,否则启动时在DatabaseInit阶段报「不支持的数据库驱动」。接入自定义驱动(TiDB / ClickHouse 等)可经xOptDatabase.WithDialector直接注入,无需注册表。
v1.0.5 起,Register 与 Runner 均接受 opts ...xOption.Option,opts 既可作为变参传给 Register(业务自定义节点立即拿到 DB / 缓存),也可切片传给 Runner(仅启动阶段装配)。两者不是二选一,而是同一套 opts 的两种注入时机:
方式 A:opts 传给 Register(推荐,业务节点立即可用)
─────────────────────────────────────────────────────
import _ "github.com/bamboo-services/bamboo-base-go/plugins/database/mysql" // 注册 MySQL 驱动
reg := xReg.Register(ctx, nodeList,
xOption.WithCache(xOptCache.WithRedis(...)),
xOption.WithDatabase(xOptDatabase.WithDriver(xOptDatabase.DriverMySQL, "user:pass@tcp(localhost:3306)/db")),
xOption.WithRoute(routeFunc),
)
xMain.Runner(reg, log, nil)
方式 B:opts 传给 Runner(启动阶段才装配)
─────────────────────────────────────────────────────
import _ "github.com/bamboo-services/bamboo-base-go/plugins/database/mysql" // 注册 MySQL 驱动
reg := xReg.Register(ctx, nodeList)
opts := []xOption.Option{
xOption.WithCache(xOptCache.WithRedis(...)),
xOption.WithDatabase(xOptDatabase.WithDriver(xOptDatabase.DriverMySQL, "user:pass@tcp(localhost:3306)/db")),
xOption.WithRoute(routeFunc),
}
xMain.Runner(reg, log, opts)两层调用形态
v1.0.4 起,缓存与数据库采用对称的「两层调用」设计,将类型/配置构造收敛到 xOptCache / xOptDatabase 子包,父包 xOption 仅保留 WithCache / WithDatabase 顶层入口与类型别名重导出:
xOption.WithCache(xOptCache.WithRedis("localhost:6379"))
└─ 父包 Option └─ 子包 CacheOption(具体后端构造)
xOption.WithDatabase(xOptDatabase.WithDriver(xOptDatabase.DriverMySQL, "user:pass@tcp(...)/db"))
└─ 父包 Option └─ 子包 DatabaseOption(具体驱动构造,v1.2.0 起驱动插件化)| 维度 | 父包(xOption) | 子包(xOptCache / xOptDatabase) |
|---|---|---|
| 类型别名 | CacheType / Driver / CacheConfig / DatabaseConfig | 子包原定义 |
| 顶层入口 | WithCache / WithDatabase / WithRoute | — |
| 后端构造 | — | WithRedis / WithMemory / WithDriver / WithDialector / FromEnv 等 |
| 二级选项 | — | WithRedisPassword / WithMaxOpenConns / WithAutoMigrate 等 |
父包对常用类型做了别名重导出(如
xOption.DriverMySQL、xOption.CacheTypeRedis),保证旧引用xOption.DriverXXX仍可编译;但配置构造(WithDriver/WithRedis/FromEnv等)请直接走子包,避免父包冗余包装。
核心类型
Option & Config
// Option 是应用级配置选项的函数签名
type Option func(*Config)
// Config 是应用运行期配置的聚合体,字段均私有,仅通过 getter 暴露只读视图
type Config struct { /* 私有字段 */ }
func (c *Config) Cache() CacheConfig // 缓存配置
func (c *Config) Database() xOptDatabase.DatabaseConfig // 数据库配置
func (c *Config) Routes() []RouteRegistrar // 路由注册器列表Apply
将 Option 列表逐个应用到 Config,nil 选项自动跳过。
func Apply(opts ...Option) *Config缓存配置
字段
类型
后端构造(子包 xOptCache)
字段
类型
Redis 子选项
| 选项 | 类型 | 说明 |
|---|---|---|
xOptCache.WithRedisUsername(u) | RedisOption | ACL 用户名 |
xOptCache.WithRedisPassword(p) | RedisOption | 密码 |
xOptCache.WithRedisDB(db) | RedisOption | 数据库序号 |
xOptCache.WithRedisPoolSize(n) | RedisOption | 连接池大小 |
xOptCache.WithRedisMinIdleConns(n) | RedisOption | 最小空闲连接数 |
xOptCache.WithRedisDialTimeout(d) | RedisOption | 连接建立超时 |
xOptCache.WithRedisReadTimeout(d) | RedisOption | 读操作超时 |
xOptCache.WithRedisWriteTimeout(d) | RedisOption | 写操作超时 |
Memory 子选项
| 选项 | 类型 | 说明 |
|---|---|---|
xOptCache.WithMemoryDefaultTTL(d) | MemoryOption | 默认过期时间 |
xOptCache.WithMemoryMaxEntries(n) | MemoryOption | 最大条目数 |
xOptCache.WithMemoryShardCount(n) | MemoryOption | 分片数(提升并发) |
数据库配置
字段
类型
驱动构造(子包 xOptDatabase)
v1.2.0 起,数据库驱动插件化,MySQL() / Postgres() / SQLite() / Oracle() / SQLServer() 构造函数已移除,统一收敛为 WithDriver / WithDialector 两个入口。
字段
类型
驱动枚举(
xOptDatabase.Driver,重导出自common/database):DriverNone/DriverMySQL/DriverPostgres/DriverSQLite/DriverOracle/DriverSQLServer。零值空串等价于DriverNone,表示不启用数据库。
必须导入驱动插件:
WithDriver与FromEnv只负责驱动枚举与 DSN 字符串,打开连接时DatabaseInit需按枚举从注册表解析工厂,因此必须空白导入对应驱动插件(如_ "github.com/bamboo-services/bamboo-base-go/plugins/database/mysql"),否则启动阶段报「不支持的数据库驱动」。各插件对应关系见下表。
| 驱动 | 插件 import(空白导入) | DSN 格式 |
|---|---|---|
| MySQL | _ "…/plugins/database/mysql" | user:pass@tcp(host:3306)/db?charset=utf8mb4&parseTime=True |
| PostgreSQL | _ "…/plugins/database/postgres" | PG 连接串(见 PostgresFromEnv) |
| SQLite | _ "…/plugins/database/sqlite" | 文件路径或 :memory: |
| Oracle | _ "…/plugins/database/oracle" | godror logfmt 格式(需 Oracle Instant Client) |
| SQL Server | _ "…/plugins/database/sqlserver" | sqlserver://user:pass@host:port?database=db |
Oracle DSN 格式
WithDriver(xOptDatabase.DriverOracle, dsn) 接受 godror logfmt 格式连接串:
user="scott" password="tiger" connectString="dbhost:1521/orclpdb1" libDir="/path/to/instantclient"平台差异:Oracle 驱动底层为 godror(ODPI-C),依赖 Oracle Instant Client。
- macOS / Windows:必须通过
libDir字段或环境变量DATABASE_LIB_DIR指定 Instant Client 库目录。- Linux:留空
libDir,改用ldconfig将 Instant Client 加入系统库搜索路径。如需从环境变量自动拼装,改用
xOptDatabase.FromEnv()并设置DATABASE_DRIVER=oracle,同时空白导入plugins/database/oracle插件。
SQL Server DSN 格式
WithDriver(xOptDatabase.DriverSQLServer, dsn) 接受 URL 格式连接串:
sqlserver://user:pass@host:port?database=dbname通用二级选项
| 选项 | 类型 | 说明 |
|---|---|---|
xOptDatabase.WithMaxOpenConns(n) | DatabaseOption | 最大打开连接数 |
xOptDatabase.WithMaxIdleConns(n) | DatabaseOption | 最大空闲连接数 |
xOptDatabase.WithConnMaxLifetime(d) | DatabaseOption | 连接最大存活时间 |
xOptDatabase.WithConnMaxIdleTime(d) | DatabaseOption | 连接最大空闲时间 |
xOptDatabase.WithTablePrefix(p) | DatabaseOption | 表名前缀(FromEnv 已自动读 DATABASE_PREFIX) |
xOptDatabase.WithAutoMigrate(tables...) | DatabaseOption | AutoMigrate 目标表(可多次叠加) |
xOptDatabase.WithPrepare(fns...) | DatabaseOption | 建表后数据初始化回调(按注册顺序执行) |
路由配置
字段
类型
// RouteRegistrar 路由注册器,接收已装配依赖的 ctx(含 DB/缓存等组件)与 Gin 引擎进行路由挂载
type RouteRegistrar func(ctx context.Context, serve *gin.Engine)使用示例
完整配置(Redis + MySQL + 路由)
package main
import (
"context"
"time"
xLog "github.com/bamboo-services/bamboo-base-go/common/log"
xMain "github.com/bamboo-services/bamboo-base-go/major/main"
xOption "github.com/bamboo-services/bamboo-base-go/major/option"
xOptCache "github.com/bamboo-services/bamboo-base-go/major/option/cache"
xOptDatabase "github.com/bamboo-services/bamboo-base-go/major/option/database"
xReg "github.com/bamboo-services/bamboo-base-go/major/register"
// v1.2.0 起驱动插件化:空白导入 MySQL 驱动触发注册
_ "github.com/bamboo-services/bamboo-base-go/plugins/database/mysql"
)
func main() {
// v1.0.5 起:opts 直接通过变参传给 Register(方式 A,推荐)
reg := xReg.Register(context.Background(), nil,
// 缓存:Redis 后端
xOption.WithCache(xOptCache.WithRedis("localhost:6379",
xOptCache.WithRedisPassword("xxx"),
xOptCache.WithRedisDB(0),
)),
// 数据库:MySQL(v1.2.0 起用 WithDriver 替代 MySQL() 构造函数)
xOption.WithDatabase(xOptDatabase.WithDriver(
xOptDatabase.DriverMySQL,
"user:pass@tcp(localhost:3306)/bamboo?charset=utf8mb4&parseTime=True",
)),
// 路由
xOption.WithRoute(func(ctx context.Context, serve *gin.Engine) {
serve.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
}),
)
log := xLog.WithName(xLog.NamedMAIN)
// Runner 根据 opts 自动装配 Redis 客户端、GORM DB 等
xMain.Runner(reg, log, nil)
// 也支持传入后台协程函数
// xMain.Runner(reg, log, nil, goroutineFunc)
}仅缓存 + Memory 后端
reg := xReg.Register(context.Background(), nil,
xOption.WithCache(xOptCache.WithMemory(
xOptCache.WithMemoryDefaultTTL(10*time.Minute),
xOptCache.WithMemoryMaxEntries(10000),
)),
xOption.WithRoute(func(ctx context.Context, serve *gin.Engine) {
serve.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
})
}),
)
xMain.Runner(reg, log, nil)Oracle 数据库
// v1.2.0 起需空白导入 Oracle 驱动插件(底层 godror,需 CGO 与 Instant Client)
import _ "github.com/bamboo-services/bamboo-base-go/plugins/database/oracle"
reg := xReg.Register(context.Background(), nil,
// Oracle:显式 DSN(macOS/Windows 必须包含 libDir)
xOption.WithDatabase(xOptDatabase.WithDriver(
xOptDatabase.DriverOracle,
`user="scott" password="tiger" connectString="dbhost:1521/orclpdb1" libDir="/opt/oracle/instantclient"`,
xOptDatabase.WithMaxOpenConns(50),
)),
xOption.WithRoute(routeFunc),
)
xMain.Runner(reg, log, nil)SQL Server 数据库
// v1.2.0 起需空白导入 SQL Server 驱动插件
import _ "github.com/bamboo-services/bamboo-base-go/plugins/database/sqlserver"
reg := xReg.Register(context.Background(), nil,
// SQL Server:URL 格式连接串
xOption.WithDatabase(xOptDatabase.WithDriver(
xOptDatabase.DriverSQLServer,
"sqlserver://sa:Pa55w0rd@localhost:1433?database=mydb",
)),
xOption.WithRoute(routeFunc),
)
xMain.Runner(reg, log, nil)从环境变量装配(缓存 + 数据库)
import (
xOption "github.com/bamboo-services/bamboo-base-go/major/option"
xOptCache "github.com/bamboo-services/bamboo-base-go/major/option/cache"
xOptDatabase "github.com/bamboo-services/bamboo-base-go/major/option/database"
// v1.2.0 起:FromEnv 也需按 DATABASE_DRIVER 导入对应驱动插件
// DATABASE_DRIVER=postgres 时导入:
_ "github.com/bamboo-services/bamboo-base-go/plugins/database/postgres"
)
reg := xReg.Register(context.Background(), nil,
// 读取 NOSQL_DRIVER 等;未设置时闭包不修改 Config,等价于不启用缓存
xOption.WithCache(xOptCache.FromEnv()),
// 读取 DATABASE_DRIVER/DATABASE_HOST/... 等,按驱动自动选择拼装函数
// 支持 mysql / postgres / sqlite / oracle / sqlserver(须导入对应驱动插件)
xOption.WithDatabase(
xOptDatabase.FromEnv(),
xOptDatabase.WithAutoMigrate(&entity.Role{}, &entity.User{}),
xOptDatabase.WithPrepare(seedRoles),
),
xOption.WithRoute(routeFunc),
)
xMain.Runner(reg, log, nil)条件构造
nil Option 与 nil 子包二级选项都会被自动跳过,可安全用于条件分支:
var opts []xOption.Option
if useRedis {
// cond && WithCache(...) 短路求值:false 时整体为 nil,被 Apply 跳过
opts = append(opts, useRedis && xOption.WithCache(xOptCache.WithRedis("localhost:6379")))
} else {
opts = append(opts, xOption.WithCache(xOptCache.WithMemory()))
}
opts = append(opts, xOption.WithRoute(routeFunc))
// 将累积的 opts 作为变参展开传给 Register
reg := xReg.Register(context.Background(), nil, opts...)
xMain.Runner(reg, log, nil)与注册节点模式的关系
xOption 是注册节点模式的补充,而非替代。两者可以共存:
| 场景 | 推荐方式 |
|---|---|
| 框架内置组件(缓存、数据库、路由) | xOption |
| 自定义初始化逻辑(第三方 SDK、业务启动) | xRegNode |
| 需要访问前序节点结果 | xRegNode(节点化注入) |
// 混合模式:内置组件用 Option,自定义逻辑用节点
reg := xReg.Register(ctx,
[]xRegNode.RegNodeList{
{Key: xCtx.CustomClientKey, Node: initCustomSDK},
},
// v1.0.5 起:opts 可直接作为变参传给 Register
xOption.WithCache(xOptCache.WithRedis("localhost:6379")),
xOption.WithRoute(routeFunc),
)
xMain.Runner(reg, log, nil)