运行时依赖
安装命令
点击复制技能文档
角色:您是一名使用wire进行编译时依赖注入的Go架构师。您让编译器捕获缺失的依赖项,将wire_gen.go视为提交的源代码,并在每次图形更改后重新运行wire ./...。使用google/wire进行Go代码的编译时依赖注入。Wire在编译时解析依赖图并发出纯Go构造函数调用——无运行时容器,无反射。错误出现在运行wire ./...时,而不是第一次请求时。注意:google/wire在2025年8月被归档(功能完整;仍然接受错误修复)。官方资源:pkg.go.dev · github.com/google/wire · 用户指南 · 最佳实践。本技能并不详尽。请参考库文档和代码示例以获取更多信息。Context7可以作为发现平台提供帮助。go install github.com/google/wire/cmd/wire@latest go get github.com/google/wire wire与运行时DI的比较:
| wire | 运行时DI | |
|---|---|---|
| 解析时间 | 编译时(代码生成) | 运行时(反射) |
| 错误检测 | wire ./...失败 | 首次调用/启动时 |
| 运行时容器 | 无——纯Go调用 | 存在 |
| 生命周期钩子 | 不内置 | fx:OnStart/OnStop |
| 生成文件 | wire_gen.go(提交) | 无 |
func NewConfig() Config { return &Config{Addr: ":8080"} }
func NewDB(cfg Config) (sql.DB, error) { return sql.Open("postgres", cfg.DSN) }
func NewRedis(cfg Config) (redis.Client, func(), error) {
// cleanup链式调用以反向顺序
c := redis.NewClient(&redis.Options{Addr: cfg.RedisAddr})
return c, func() { c.Close() }, nil
}
提供者集:
wire.NewSet将提供者分组以便重用。集可以引用其他集。
保持集小:库集暴露稳定的表面(添加输入或删除输出会破坏下游注入器)。每个包一个集是一个有用的默认值。// infra/wire.go var InfraSet = wire.NewSet( NewConfig, NewDB, NewRedis, )
// service/wire.go var ServiceSet = wire.NewSet( NewUserRepo, NewUserService, wire.Bind(new(UserStore), new(UserRepo)), // 接口绑定 )
注入器: 注入器文件声明初始化函数。Wire生成其主体到wire_gen.go并替换stub。
//go:build wireinject
package main
import "github.com/google/wire"
// Wire生成此函数的主体。
func InitApp() (App, func(), error) {
wire.Build(InfraSet, ServiceSet, NewApp)
return nil, nil, nil // 由代码生成替换
}
//go:build wireinject标签防止stub被编译到二进制文件中——只有wire_gen.go(没有此标签)通过go build。没有此标签,两个文件定义同一个函数,导致编译错误。
替代语法,当dummy返回不方便时:
接口绑定: Wire禁止隐式接口满足——您必须显式声明绑定,以便图形在多个类型实现同一接口时保持明确。func InitApp() (App, func(), error) { panic(wire.Build(InfraSet, ServiceSet, NewApp)) }
var Set = wire.NewSet(
NewPostgresUserRepo,
wire.Bind(new(UserStore), new(PostgresUserRepo)), // 告诉wire:PostgresUserRepo满足UserStore
)
显式绑定防止图形在其他地方添加新类型实现同一接口时破坏。
结构提供者和值:
wire.Struct从图中填充结构字段,而无需手动构造函数。标记字段wire:"-"以排除它们。
wire.Struct(new(Server), "Logger", "DB") // 注入命名字段
wire.Struct(new(Server), "") // 注入所有非排除字段
wire.Value(Foo{X: 42}) // 常量表达式(无函数调用/通道)
wire.InterfaceValue(new(io.Reader), os.Stdin) // 接口类型字面量
wire.FieldsOf(new(Config), "DSN", "Addr") // 提升结构字段作为图节点
请参阅advanced.md以获取wire:"-"排除标签和wire.FieldsOf详细信息。
消除重复类型:
Wire禁止同一类型的两个提供者。将底层类型包装在不同的命名类型中,以便每个类型都有一个提供者:
type PrimaryDSN string
type ReplicaDSN string
完整应用示例:
Wire生成wire_gen.go(纯Go,提交,勿编辑)。有关每个包的集、清理密集图和生成输出的完整示例,请参阅recipes.md。 代码生成工作流: wire ./... # 重新生成所有注入器在模块中// wire.go —— 注入器,通过构建标签排除在二进制文件之外 //go:build wireinject package main func InitApp() (App, func(), error) { wire.Build(config.ConfigSet, infra.InfraSet, service.ServiceSet, NewApp) return nil, nil, nil }
// main.go func main() { app, cleanup, err := InitApp() if err != nil { log.Fatal(err) } defer cleanup() app.Run() }