Help us shape the future of Go! Take the 2026 Go Developer Survey

betterdep

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 2 Imported by: 1

README

betterdep | 基于 map + Go 泛型的轻量依赖注入 (DI) 系统

内部就是一张 sync.Map, 仅此而已

开始使用

go get github.com/UnknownMp391/betterdep

要求 Go 1.18+ (泛型)

特性

创建依赖: Dependency[T]

用 betterdep.Dependency[T]{Identifier, Resolver} 描述一个依赖, 泛型参数 T 是依赖实例的类型

Resolver 签名: func(*DependencyManager) (T, func(), error), 第三个返回值是 dispose 函数, 可为 nil

type DB struct {
    dsn string
}

func (db *DB) Close() {
    fmt.Println("db closed")
}

// 无资源需要释放时, dispose 函数返回 nil
var ConfigProvider betterdep.Dependency[string] = betterdep.Dependency[string]{
    Identifier: "config",
    Resolver: func(dp *betterdep.DependencyManager) (string, func(), error) {
        return "app.db", nil, nil
    },
}

// 持有资源的依赖, 返回 dispose 函数, Dispose 时统一调用
var DBProvider betterdep.Dependency[*DB] = betterdep.Dependency[*DB]{
    Identifier: "db",
    Resolver: func(dp *betterdep.DependencyManager) (*DB, func(), error) {
        // Resolver 内部可以继续解析其他依赖, 实现依赖组合
        dsn, err := betterdep.Provide(dp, &ConfigProvider)
        if err != nil {
            return nil, nil, err
        }

        db := &DB{dsn: dsn}
        return db, func() { db.Close() }, nil
    },
}
解析依赖: Provide

betterdep.Provide(manager, &dep) 解析并缓存依赖, 同一个 Identifier 的 resolver 只会被调用一次

  • resolver 出错时, 原样返回该 error
  • 缓存中的实例类型与 T 不一致时, 返回类型不匹配的 error
dp := betterdep.NewDependencyManager()
defer dp.Dispose()

calls := 0
var CounterProvider betterdep.Dependency[int] = betterdep.Dependency[int]{
    Identifier: "counter",
    Resolver: func(dp *betterdep.DependencyManager) (int, func(), error) {
        calls++
        return calls, nil, nil
    },
}

v1, err := betterdep.Provide(dp, &CounterProvider)
if err != nil {
    log.Fatal(err)
}

v2, _ := betterdep.Provide(dp, &CounterProvider) // 命中缓存, resolver 不再执行

fmt.Println(v1, v2) // 1 1
预注册与手动注册: PreRegister / Register
  • PreRegister: 立即调用 resolver 解析并缓存依赖, 启动阶段提前暴露配置错误, resolver 出错时返回 error
  • Register: 实例已构建好, 直接存入缓存, 不调用 resolver
type Config struct {
    DSN string
}

dp := betterdep.NewDependencyManager()
defer dp.Dispose()

// 预注册: 启动时提前解析, 尽早暴露错误
if err := betterdep.PreRegister(dp, DBProvider); err != nil {
    log.Fatal(err)
}

// 手动注册: 跳过 resolver, 直接使用已有实例
betterdep.Register(dp, betterdep.Dependency[Config]{
    Identifier: "app-config",
}, Config{DSN: "app.db"}, nil)
释放资源: Dispose

Dispose 按注册顺序调用所有 dispose 函数, 然后清空缓存与 dispose 列表, 管理器可复用

disposed := 0

var ResProvider betterdep.Dependency[string] = betterdep.Dependency[string]{
    Identifier: "resource",
    Resolver: func(dp *betterdep.DependencyManager) (string, func(), error) {
        return "resource", func() { disposed++ }, nil
    },
}

dp := betterdep.NewDependencyManager()
if _, err := betterdep.Provide(dp, &ResProvider); err != nil {
    log.Fatal(err)
}

dp.Dispose() // 调用所有注册的 dispose 函数
fmt.Println(disposed) // 1
典型用法: 全局单例 vs 请求单例
  • 全局单例: 进程级 manager, 整个进程共享同一份依赖
  • 请求单例: 每个请求新建 manager, defer Dispose 在请求结束后自动释放
// 全局单例: 进程启动时创建一次
var global = betterdep.NewDependencyManager()

func GetDB() *DB {
    db, err := betterdep.Provide(global, &DBProvider)
    if err != nil {
        panic(err)
    }
    return db
}

// 请求单例: 每请求新建 manager, 请求结束统一释放
func handleRequest() {
    req := betterdep.NewDependencyManager()
    defer req.Dispose()

    cfg, err := betterdep.Provide(req, &ConfigProvider)
    if err != nil {
        log.Print(err)
        return
    }
    fmt.Println(cfg)
}

Documentation

Overview

Package betterdep 是一个基于 map 与 Go 泛型实现的轻量依赖注入 (DI) 系统

它支持全局单例与请求级作用域两种典型用法, 并通过 Dispose 机制统一释放 依赖持有的资源泛型 API(Provide[T]、PreRegister[T]、Register[T]) 保证类型安全; 对应的非泛型方法内部使用 any 实现

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func PreRegister

func PreRegister[T any](dp *DependencyManager, dep Dependency[T]) error

PreRegister 立即解析并缓存一个类型安全的依赖

与 DependencyManager.PreRegister 行为一致, 但依赖类型由泛型参数 T 保证, 缓存结果与后续 Provide[T] 的类型保持一致Resolver 出错时 返回该错误, 且不缓存任何内容

func Provide

func Provide[T any](dp *DependencyManager, dep *Dependency[T]) (T, error)

Provide 解析并缓存一个类型安全的依赖

内部委托给非泛型版本 DependencyManager.Provide, 并对结果做类型断言:

  • Resolver 返回 error 时, 原样返回该 error;
  • 缓存中实例的实际类型与 T 不一致时, 返回类型不匹配的 error

同一 Identifier 在同一 manager 中只会被解析一次, 后续调用直接命中缓存

func Register

func Register[T any](dp *DependencyManager, dep Dependency[T], instance T, dispose func())

Register 直接缓存一个已构建好的类型安全实例

与 DependencyManager.Register 行为一致, 但实例类型由泛型参数 T 保证, 缓存结果与后续 Provide[T] 的类型保持一致不调用 Resolver, 已存在的 Identifier 会被忽略dispose 可为 nil

Types

type Dependency

type Dependency[T any] struct {
	// Identifier 是依赖在管理器中的唯一标识
	//
	// Provide / PreRegister / Register 均以 Identifier 为准进行缓存与查找,
	// 相同 Identifier 的依赖在同一个 DependencyManager 中只会被解析一次
	Identifier string

	// Resolver 创建依赖实例
	//
	// 签名: func(*DependencyManager) (T, func(), error)
	// 第一个返回值是依赖实例; 第二个返回值是 dispose 函数, 可为 nil;
	// 第三个返回值是错误, 非 nil 时上层调用会原样返回该错误
	// Resolver 内部可以通过 Provide 继续解析其他依赖, 实现依赖组合
	Resolver func(*DependencyManager) (T, func(), error)
}

Dependency 描述一个依赖

泛型参数 T 是依赖实例的类型Resolver 负责创建实例, 并可选地返回一个 dispose 函数, 供 DependencyManager.Dispose 在释放阶段统一调用

type DependencyManager

type DependencyManager struct {
	// Cache 存储已解析的依赖实例, 以依赖的 Identifier 为 key
	Cache sync.Map

	// DisposeFuncs 按注册顺序保存所有 dispose 函数, Dispose 时依次调用
	DisposeFuncs []func()
}

DependencyManager 管理一组依赖: 缓存已解析的实例, 并收集 dispose 函数

每次调用 NewDependencyManager 创建一个独立的作用域, 互不共享缓存

func NewDependencyManager

func NewDependencyManager() *DependencyManager

NewDependencyManager 创建一个空的依赖管理器

典型用法: 进程级 manager 提供全局单例, 或每个请求新建 manager 配合 defer Dispose 提供请求级单例

func (*DependencyManager) Dispose

func (dp *DependencyManager) Dispose()

Dispose 依次调用所有已注册的 dispose 函数, 然后清空缓存与 dispose 列表

调用后管理器回到空状态, 可以继续复用 nil 的 dispose 函数会被安全跳过

func (*DependencyManager) PreRegister

func (dp *DependencyManager) PreRegister(dep Dependency[any]) error

PreRegister 立即解析并缓存一个依赖 (非泛型版本, 内部使用 any 实现)

dep 的 Resolver 会被立刻调用一次: 成功则缓存实例并登记 dispose 函数; 失败则返回 Resolver 的错误, 且不缓存任何内容已缓存的 Identifier 不会被重复解析

需要类型安全的版本请使用包级函数 PreRegister[T]

func (*DependencyManager) Provide

func (dp *DependencyManager) Provide(dep *Dependency[any]) (any, error)

Provide 解析并缓存一个依赖 (非泛型版本, 内部使用 any 实现)

命中缓存时直接返回缓存实例; 否则调用 Resolver: 出错则原样返回错误, 成功则缓存实例 (并登记非 nil 的 dispose 函数) 后返回返回值类型为 any, 需要调用方自行断言

需要类型安全的版本请使用包级函数 Provide[T]

func (*DependencyManager) Register

func (dp *DependencyManager) Register(dep Dependency[any], instance any, dispose func())

Register 直接缓存一个已构建好的实例 (非泛型版本, 内部使用 any 实现)

不调用 Resolver仅当 Identifier 尚未被缓存时才写入, 已存在的 Identifier 会被忽略dispose 可为 nil

需要类型安全的版本请使用包级函数 Register[T]

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL