竹简文档

声明式配置

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/databasexDB),五种内置驱动(MySQL / PostgreSQL / SQLite / Oracle / SQL Server)拆分为独立插件 plugins/database/*。业务侧需 空白导入对应驱动插件 触发注册,否则启动时在 DatabaseInit 阶段报「不支持的数据库驱动」。接入自定义驱动(TiDB / ClickHouse 等)可经 xOptDatabase.WithDialector 直接注入,无需注册表。

v1.0.5 起,RegisterRunner 均接受 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.DriverMySQLxOption.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)RedisOptionACL 用户名
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,表示不启用数据库。

必须导入驱动插件WithDriverFromEnv 只负责驱动枚举与 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...)DatabaseOptionAutoMigrate 目标表(可多次叠加)
xOptDatabase.WithPrepare(fns...)DatabaseOption建表后数据初始化回调(按注册顺序执行)

路由配置

字段

类型

// RouteRegistrar 路由注册器,接收已装配依赖的 ctx(含 DB/缓存等组件)与 Gin 引擎进行路由挂载
type RouteRegistrar func(ctx context.Context, serve *gin.Engine)

使用示例

完整配置(Redis + MySQL + 路由)

main.go
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 数据库

main.go
// 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 数据库

main.go
// 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)

下一步

On this page