初始化
上下文注入
通过节点化系统和中间件实现上下文资源注入
上下文注入
新版本采用节点化系统实现上下文资源注入,取代了原有的 SystemContextInit 方法。
注入机制
节点化注入(初始化时)
在 Register 时通过自定义节点注入全局资源:
import (
"context"
xCtx "github.com/bamboo-services/bamboo-base-go/defined/context"
xReg "github.com/bamboo-services/bamboo-base-go/major/register"
xRegNode "github.com/bamboo-services/bamboo-base-go/major/register/node"
)
func main() {
reg := xReg.Register(context.Background(), []xRegNode.RegNodeList{
{Key: xCtx.DatabaseKey, Node: initDatabase},
{Key: xCtx.RedisClientKey, Node: initRedis},
})
reg.Serve.Run(":8080")
}中间件注入(请求时)
xHelper.RequestContext() 中间件为每个请求注入请求级数据:
func RequestContext() gin.HandlerFunc {
return func(c *gin.Context) {
// 生成请求唯一标识
requestID := uuid.New().String()
// 记录请求开始时间
startTime := time.Now()
// 注入到上下文
ctx := c.Request.Context()
ctx = context.WithValue(ctx, xCtx.RequestKey, requestID)
ctx = context.WithValue(ctx, xCtx.UserStartTimeKey, startTime)
c.Request = c.Request.WithContext(ctx)
c.Next()
}
}上下文合并
injectContext 中间件将初始化上下文合并到每个请求:
func injectContext(ctx context.Context) func(c *gin.Context) {
return func(c *gin.Context) {
// 将初始化上下文(包含 DB、Redis、Snowflake 等)注入到请求
c.Request = c.Request.WithContext(ctx)
c.Next()
}
}注入的资源
| 资源 | Key | 类型 | 注入时机 |
|---|---|---|---|
| 雪花算法节点 | SnowflakeNodeKey | *xSnowflake.Node | 内置节点(自动) |
| 数据库连接 | DatabaseKey | *gorm.DB | 自定义节点 |
| Redis 客户端 | RedisClientKey | *redis.Client | 自定义节点 |
| 请求 ID | RequestKey | string | 请求中间件 |
| 开始时间 | UserStartTimeKey | time.Time | 请求中间件 |
获取上下文资源
使用 xCtxUtil 包从上下文获取注入的资源:
import xCtxUtil "github.com/bamboo-services/bamboo-base-go/common/utility/context"
func CreateOrder(c *gin.Context) {
// 获取标准上下文
ctx := c.Request.Context()
// 获取数据库连接
db := xCtxUtil.MustGetDB(ctx)
// 获取 Redis 客户端
rdb := xCtxUtil.MustGetRDB(ctx)
// 获取雪花算法节点
node := xCtxUtil.GetSnowflakeNode(ctx)
// 生成订单 ID
orderID := node.MustGenerate(xSnowflake.GeneOrder)
}自定义初始化节点
创建自定义初始化节点的标准模式:
import (
"context"
xLog "github.com/bamboo-services/bamboo-base-go/common/log"
)
// 初始化节点函数签名:func(ctx context.Context) (any, error)
func initDatabase(ctx context.Context) (any, error) {
log := xLog.WithName(xLog.NamedINIT)
log.Info(ctx, "初始化数据库连接")
// 构建 DSN
dsn := buildDSN()
// 创建数据库连接
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
log.Info(ctx, "数据库连接成功")
// 返回值将被存入上下文
return db, nil
}请求 ID
每个请求都会自动生成唯一的请求 ID:
func GetRequestID(c *gin.Context) string {
return xCtxUtil.GetRequestKey(c.Request.Context())
}请求 ID 会:
- 存储在上下文中,通过
xCtx.RequestKey访问 - 添加到响应头
X-Request-ID - 用于日志追踪和问题排查
迁移指南
从旧版本迁移:
| 旧版本 | 新版本 |
|---|---|
xReg.SystemContextInit() | 节点化系统自动处理 |
c.Set(key, value) | context.WithValue() |
c.Get(key) | ctx.Value(key) |
xCtxUtil.GetDB(c) | xCtxUtil.MustGetDB(c.Request.Context()) |