# Go Wire 依次依赖注入原理与 Demo
本文通过一个完整 Demo,系统整理 Go Wire 的“依次 / 链式依赖注入”机制:
上一个 Provider 的 return 值,如何自动作为下一个 Provider 的参数。
一、什么是 Wire 的「依次依赖注入」
一句话概括:
Wire 会根据“返回值类型 → 参数类型”的匹配关系,自动把多个构造函数串成一条调用链,并在编译期生成代码。
它不是:
- 运行时容器
- 反射注入
- 黑盒魔法
而是:
- 构建依赖图(Dependency Graph)
- 排序依赖
- 生成明确的 Go 构造代码
二、一个最典型的依赖链
假设我们有如下对象层级:
App |
对应的构造函数:
func NewDB() *sql.DB |
这里已经完整声明了“依次依赖关系”:
NewDB返回*sql.DBNewUserRepo需要*sql.DBNewUserService需要*UserRepoNewApp需要*UserService
三、Wire Build:只声明,不传参
初始化函数(通常写在 wire.go):
//go:build wireinject |
注意:
- 没有参数传递
- 没有顺序要求
- 只声明「有哪些 Provider」
四、Wire 生成的代码(关键)
运行:
wire |
生成代码(简化后):
func InitializeApp() *App { |
👉 这就是 “依次依赖注入” 的真实形态:
上一个 Provider 的 return,自动作为下一个 Provider 的参数
五、依次注入的 4 条核心规则
1️⃣ 只看类型,不看顺序
wire.Build( |
即使顺序是乱的:
- Wire 也会先建依赖图
- 再自动排序
2️⃣ 一个返回值,可以被多个依赖复用
func NewDB() *sql.DB |
生成代码:
db := NewDB() |
3️⃣ 多返回值(error)也能参与链式注入
func NewDB() (*sql.DB, error) |
生成代码:
db, err := NewDB() |
Wire 会:
- 自动处理 error
- 中断后续依赖构造
4️⃣ interface 注入,本质仍是 return → param
type UserRepo interface { |
var RepoSet = wire.NewSet( |
真实链路是:
*sql.DB |
Bind 不创建对象,只做类型映射。
六、Wire 的本质模型(重要)
Wire 在编译期做了三件事:
- 收集 Provider 的:输入类型 & 输出类型
- 构建依赖有向图(DAG)
- 按拓扑顺序生成构造代码
所以它能:
- 检测缺失依赖
- 检测循环依赖
- 保证构造顺序 100% 正确
七、为什么说这是“很 Go 的 DI”
因为:
- 没有反射
- 没有运行时容器
- 没有隐式魔法
- 生成的代码你完全可以手写
Wire 只是:
把“你本来就该写的构造代码”,按类型规则,自动帮你写出来,并保证写得对。
八、结语
Wire 的依次依赖注入,并不是概念,而是明确的代码生成规则:
Provider 的 return 值 → 按类型 → 作为下一个 Provider 的参数 → 串成完整构造链
理解这一点,Wire 基本就通了。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Leon!
评论



