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