返回顶部
g

golang-dependency-injectionGo依赖注入指南

Comprehensive guide for dependency injection (DI) in Golang. Covers why DI matters (testability, loose coupling, separation of concerns, lifecycle management), manual constructor injection, and DI library comparison (google/wire, uber-go/dig, uber-go/fx, samber/do). Use this skill when designing service architecture, setting up dependency injection, refactoring tightly coupled code, managing singletons or service factories, or when the user asks about inversion of control, service containers, or

作者: admin | 来源: ClawHub
源自
ClawHub
版本
V 1.1.2
安全检测
已通过
168
下载量
免费
免费
0
收藏
概述
安装方式
版本历史

golang-dependency-injection

角色设定: 你是一位 Go 软件架构师。你引导团队走向可测试、松耦合的设计——你选择能解决问题的最简单的依赖注入方法,并且从不过度设计。

模式:

  • - 设计模式(新项目、新服务,或向现有依赖注入设置中添加服务):评估现有依赖图和生命周期需求;根据决策表推荐手动注入或使用某个库;然后生成连接代码。
  • 重构模式(现有耦合代码):使用最多 3 个并行子代理——代理 1 识别全局变量和 init() 服务设置,代理 2 映射应成为接口的具体类型依赖,代理 3 定位服务定位器反模式(作为参数传递的容器)——然后整合发现结果并提出迁移计划。

社区默认。 一个明确取代 samber/cc-skills-golang@golang-dependency-injection 技能的公司技能具有优先权。

Go 中的依赖注入

依赖注入意味着将依赖项传递给组件,而不是让组件自己创建或查找它们。在 Go 中,这是构建可测试、松耦合应用程序的方式——你的服务声明它们需要什么,然后调用者(或容器)提供它们。

此技能并非详尽无遗。当使用依赖注入库(google/wire、uber-go/dig、uber-go/fx、samber/do)时,请参考该库的官方文档和代码示例以获取最新的 API 签名。

关于基于接口的设计基础(接受接口,返回结构体),请参阅 samber/cc-skills-golang@golang-structs-interfaces 技能。

最佳实践总结

  1. 1. 依赖项必须通过构造函数注入——绝不要使用全局变量或 init() 进行服务设置
  2. 小型项目(少于 10 个服务)应该使用手动构造函数注入——不需要库
  3. 接口必须在消费处定义,而不是在实现处定义——接受接口,返回结构体
  4. 绝不要使用全局注册表或包级服务定位器
  5. 依赖注入容器必须只存在于组合根(main() 或应用启动处)——绝不要将容器作为依赖项传递
  6. 优先使用懒初始化——仅在首次请求时创建服务
  7. 对有状态的服务使用单例(数据库连接、缓存),对无状态的服务使用瞬态
  8. 在接口边界进行模拟——依赖注入使这变得非常简单
  9. 保持依赖图浅层——深层链表明设计存在问题
  10. 根据项目规模和团队选择合适的依赖注入库——请参阅下面的决策表

为什么要使用依赖注入?

没有依赖注入的问题依赖注入如何解决
函数创建自己的依赖项依赖项被注入——可以自由切换实现
测试需要真实的数据库、API
在测试中传递模拟实现 | | 更改一个组件会破坏其他组件 | 通过接口实现松耦合——组件不知道彼此的内部实现 | | 服务随处初始化 | 集中式容器管理生命周期(单例、工厂、懒加载) | | 所有服务在启动时加载 | 懒加载——仅在首次请求时创建服务 | | 全局状态和 init() 函数 | 在启动时显式连接——可预测、可调试 |

依赖注入在具有许多相互连接服务的应用程序中表现出色——HTTP 服务器、微服务、带有插件的 CLI 工具。对于只有 2-3 个函数的小脚本,手动连接就足够了。不要过度设计。

手动构造函数注入(无库)

对于小型项目,通过构造函数传递依赖项。请参阅 手动 DI 示例 以获取完整的应用程序示例。

go
// ✓ 好——显式依赖,可测试
type UserService struct {
db UserStore
mailer Mailer
logger *slog.Logger
}

func NewUserService(db UserStore, mailer Mailer, logger slog.Logger) UserService {
return &UserService{db: db, mailer: mailer, logger: logger}
}

// main.go — 手动连接
func main() {
logger := slog.Default()
db := postgres.NewUserStore(connStr)
mailer := smtp.NewMailer(smtpAddr)
userSvc := NewUserService(db, mailer, logger)
orderSvc := NewOrderService(db, logger)
api := NewAPI(userSvc, orderSvc, logger)
api.ListenAndServe(:8080)
}

go
// ✗ 坏——硬编码依赖,不可测试
type UserService struct {
db *sql.DB
}

func NewUserService() *UserService {
db, := sql.Open(postgres, os.Getenv(DATABASEURL)) // 隐藏依赖
return &UserService{db: db}
}

手动依赖注入在以下情况下会失效:

  • - 你有 15 个以上具有交叉依赖的服务
  • 你需要生命周期管理(健康检查、优雅关闭)
  • 你想要懒初始化或作用域容器
  • 连接顺序变得脆弱且难以维护

依赖注入库比较

Go 主要有三种依赖注入库的方法:

决策表

标准手动google/wireuber-go/dig + fxsamber/do
项目规模小(少于 10 个服务)中-大任意规模
类型安全
编译时 | 编译时(代码生成) | 运行时(反射) | 编译时(泛型) | | 代码生成 | 无 | 需要(wire_gen.go) | 无 | 无 | | 反射 | 无 | 无 | 有 | 无 | | API 风格 | 不适用 | 提供者集合 + 构建标签 | 结构体标签 + 装饰器 | 简单、通用的函数 | | 懒加载 | 手动 | 不适用(全部即时) | 内置(fx) | 内置 | | 单例 | 手动 | 内置 | 内置 | 内置 | | 瞬态/工厂 | 手动 | 手动 | 内置 | 内置 | | 作用域/模块 | 手动 | 提供者集合 | 模块系统(fx) | 内置(层级) | | 健康检查 | 手动 | 手动 | 手动 | 内置接口 | | 优雅关闭 | 手动 | 手动 | 内置(fx) | 内置接口 | | 容器克隆 | 不适用 | 不适用 | 不适用 | 内置 | | 调试 | 打印语句 | 编译错误 | fx.Visualize() | ExplainInjector(),Web 界面 | | Go 版本 | 任意 | 任意 | 任意 | 1.18+(泛型) | | 学习曲线 | 无 | 中等 | 高 | 低 |

快速比较:同一个应用,四种方式

依赖图:Config -> Database -> UserStore -> UserService -> API

手动:

go
cfg := NewConfig()
db := NewDatabase(cfg)
store := NewUserStore(db)
svc := NewUserService(store)
api := NewAPI(svc)
api.Run()
// 没有自动关闭、健康检查或懒加载

google/wire:

go
// wire.go — 然后运行: wire ./...
func InitializeAPI() (*API, error) {
wire.Build(NewConfig, NewDatabase, NewUserStore, NewUserService, NewAPI)
return nil, nil
}
// 不支持关闭或健康检查

uber-go/fx:

go
app := fx.New(
fx.Provide(NewConfig, NewDatabase, NewUserStore, NewUserService),
fx.Invoke(func(api *API) { api.Run() }),
)
app.Run() // 管理生命周期,但基于反射

samber/do:

go
i := do.New()
do.Provide(i, NewConfig)
do.Provide(i, NewDatabase) // 自动关闭 + 健康检查
do.Provide(i, NewUserStore)
do.Provide(i, NewUserService)
api := do.MustInvoke*API
api.Run()
// defer i.Shutdown() — 自动处理所有清理工作

使用依赖注入进行测试

依赖注入使测试变得简单——注入模拟实现而不是真实实现:

go
// 定义一个模拟
type MockUserStore struct {
users map[string]*User
}

func (m MockUserStore) FindByID(ctx context.Context, id string) (User, error) {
u, ok := m.users[id]
if !ok {
return nil, ErrNotFound
}
return u, nil

标签

skill ai

通过对话安装

该技能支持在以下平台通过对话安装:

OpenClaw WorkBuddy QClaw Kimi Claude

方式一:安装 SkillHub 和技能

帮我安装 SkillHub 和 golang-dependency-injection-1776084842 技能

方式二:设置 SkillHub 为优先技能安装源

设置 SkillHub 为我的优先技能安装源,然后帮我安装 golang-dependency-injection-1776084842 技能

通过命令行安装

skillhub install golang-dependency-injection-1776084842

下载

⬇ 下载 golang-dependency-injection v1.1.2(免费)

文件大小: 14.05 KB | 发布时间: 2026-4-14 13:40

v1.1.2 最新 2026-4-14 13:40
- Added AskUserQuestion to the allowed tools, enabling interactive user prompts.
- Updated skill version to 1.1.2 in metadata.

Archiver·手机版·闲社网·闲社论坛·羊毛社区· 多链控股集团有限公司 · 苏ICP备2025199260号-1

Powered by Discuz! X5.0   © 2024-2025 闲社网·线报更新论坛·羊毛分享社区·http://xianshe.com

p2p_official_large
返回顶部