Golang Google Wire

Polar Sponsor
爱发电 赞助
.NET 9.0

在 Go 中使用 google/wire 实现编译时依赖注入——wire.NewSet、wire.Build、wire.Bind(接口→实现)、wire.Struct、wire.Value、wire.Interface

Persona: 您是使用线条进行编译的 Go 建筑师

功能概述

Persona: 您是使用线条进行编译的 Go 建筑师是一项面向实际任务的技能,主要用于您让编译器捕捉缺失的依赖性, 将线条 gen. go 当作承诺源, 并重运行线条。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。

核心要点

  • 使用时应结合输入条件选择合适的执行方式,核对必要参数、依赖环境与输出内容,并按原始要求处理异常情况。
  • 该技能适合需要稳定复用相关能力的场景,可作为自动化工作流的一部分,也便于后续检查、调整和扩展。
  • 从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。

使用与执行

实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。

结果检查与注意事项

执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。

角色:你是一位使用 wire 实现编译期依赖注入(DI)的 Go 架构师。你依赖编译器捕获缺失依赖,将 wire_gen.go 视为已提交的源码,并在每次依赖图变更后重新运行 wire ./...

依赖项:

  • wire:go install github.com/google/wire/cmd/wire@latest

在 Go 中使用 google/wire 实现编译期依赖注入

一种基于代码生成的 DI 工具包。wire 在编译期解析依赖图,并生成标准 Go 构造函数调用——不依赖运行时容器,也不使用反射。错误会在你执行 wire ./... 时暴露,而非在首次请求时才出现。

注意:google/wire 已于 2025 年 8 月归档(功能已完成;仍接受 Bug 修复)。

官方资源:pkg.go.dev · github.com/google/wire · 用户指南 · 最佳实践

本技能文档并非详尽无遗。请参考库的官方文档与代码示例获取更多信息。Context7 可作为可发现性平台提供辅助。

go get -tool github.com/google/wire/cmd/wire@latest
go get github.com/google/wire

wire 与运行时 DI 对比

关注点 wire dig / fx / samber/do
解析时机 编译期(代码生成) 运行时(反射)
错误检测 wire ./... 执行失败 首次 Invoke/启动时
运行时容器 无——纯 Go 调用 存在
生命周期钩子 未内置支持 fx: OnStart/OnStop
生成文件 wire_gen.go(需提交)

有关生命周期管理、懒加载及完整能力矩阵,请参阅 samber/cc-skills-golang@golang-dependency-injection

Provider(提供者)

Provider 是任意 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) { // 清理函数按逆序链式调用
    c := redis.NewClient(&redis.Options{Addr: cfg.RedisAddr})
    return c, func() { c.Close() }, nil
}

Provider Set(提供者集合)

wire.NewSet 将多个 Provider 组合以供复用。集合之间可相互引用。

// 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)), // 接口绑定
)

保持集合粒度细小:库级集合应暴露稳定接口(增加输入或移除输出均会破坏下游注入器)。每包一个集合是实用的默认约定。

Injector(注入器)与 //go:build wireinject

注入器文件声明初始化函数。Wire 将其函数体生成到 wire_gen.go 中,并替换原始存根。

//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 构建标签防止该存根文件被编译进二进制——仅 wire_gen.go(不含此标签)能通过 go build 编译。若缺少该标签,则两个文件均定义同名函数,导致编译错误。

当存根返回值写法不便时,可采用替代语法:

func InitApp() (*App, func(), error) {
    panic(wire.Build(InfraSet, ServiceSet, NewApp))
}

接口绑定(Interface Bindings)

Wire 禁止隐式接口实现——你必须显式声明绑定,确保当多个类型实现同一接口时,依赖图依然明确无歧义。

var Set = wire.NewSet(
    NewPostgresUserRepo,
    wire.Bind(new(UserStore), new(*PostgresUserRepo)), // 告知 Wire:*PostgresUserRepo 满足 UserStore 接口
)

显式绑定可避免因其他位置新增同接口实现类型而导致依赖图意外中断。

结构体 Provider 与值注入

wire.Struct 可直接从依赖图填充结构体字段,无需手动编写构造函数。使用 wire:"-" 标签可排除特定字段。

wire.Struct(new(Server), "Logger", "DB") // 注入指定命名字段
wire.Struct(new(Server), "*")            // 注入所有未被排除的字段
wire.Value(Foo{X: 42})                   // 常量表达式(禁止函数调用 / channel 操作)
wire.InterfaceValue(new(io.Reader), os.Stdin) // 接口类型字面量
wire.FieldsOf(new(Config), "DSN", "Addr")    // 将结构体字段提升为依赖图节点

关于 wire:"-" 排除标签与 wire.FieldsOf 的详细说明,请参阅 advanced.md。

区分重复类型(Disambiguating Duplicate Types)

Wire 禁止为同一类型注册两个 Provider。可通过为底层类型定义不同的具名类型,使每个类型恰好对应一个 Provider:

type PrimaryDSN string
type ReplicaDSN string

完整应用示例

// 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()
}

Wire 会生成 wire_gen.go(纯 Go 代码,需提交,切勿手动编辑)。含分包 Provider Set、复杂清理逻辑及生成结果的完整示例,请参阅 recipes.md。

代码生成工作流

wire ./...           # 为模块中所有注入器重新生成代码
wire check ./...     # 验证依赖图但不生成代码(适用于快速 CI 检查)

每次构造函数签名变更后都需运行 wire ./...。可在注入器文件顶部添加 //go:generate go run github.com/google/wire/cmd/wire,以便 go generate ./... 同样生效。务必提交 wire_gen.go——它必须与源码保持同步,以保障 CI 构建成功。

最佳实践

  1. 切勿手动编辑 wire_gen.go——该文件会在每次 wire ./... 运行时被完全覆盖。应将其视为已提交的构建产物;真实可信来源是 Provider 和注入器文件。
  2. 务必为所有注入器文件添加 //go:build wireinject 标签——遗漏会导致符号重复的编译错误(存根与生成文件同时定义了相同函数)。
  3. 使用具名类型区分相同底层类型的值——Wire 强制要求每种类型至多一个 Provider;例如 type DSN string 可让你共存 PrimaryDSNReplicaDSN
  4. 保持库级 Provider Set 尽可能精简且向后兼容——新增必需输入参数会破坏下游注入器;移除输出亦然。仅在同一版本中引入全新类型。
  5. 清理型 Provider 应返回 (T, func(), error),交由 Wire 自动链式调用——Wire 会生成正确逆序的清理逻辑,并妥善处理部分失败场景(若构造中途失败,仅已成功构造对象的清理函数会被执行)。
  6. 保持注入器文件职责单一——每文件一个函数,一次只导入一个包。包含数十个 wire.Build 参数的臃肿注入器难以理解;应委托给各包专属的 Provider Set。

常见错误

错误 修正方式
手动编辑 wire_gen.go 切勿编辑。修改 Provider 或注入器后,重新运行 wire ./...
遗漏 //go:build wireinject 在每个注入器文件最开头添加该标签。
两个 Provider 均返回 *sql.DB 使用具名结构体包装:type PrimaryDB struct { *sql.DB }——Wire 不区分指针类型别名。
注入接口但未使用 wire.Bind 在 Provider Set 中添加 wire.Bind(new(MyInterface), new(*MyImpl))
变更后忘记重新运行 wire ./... go build 前运行 wire;可将其加入 go generate 或 Makefile 目标。
调用 cleanup() 时未判断 nil Wire 在构造出错时返回 nil 清理函数;应使用 if cleanup != nil { defer cleanup() } 加以防护。

测试

Wire 生成的是标准 Go 构造函数,因此单元测试采用手动注入——无需克隆或重置容器。关于测试模式(如用 fake Provider 替换真实 Provider 的测试注入器、CI 中检查 wire_gen.go 是否过期),请参阅 testing.md。

延伸阅读

  • advanced.md —— 清理链、多注入器、集合嵌套、错误分类、代码生成标志、速查表
  • recipes.md —— HTTP 服务、多注入器构建、高清理负载依赖图、CLI 嵌入
  • testing.md —— 测试注入器、fake 绑定、CI 过期检查

交叉引用

  • → 参阅 samber/cc-skills-golang@golang-dependency-injection 技能,了解 DI 概念与各库对比
  • → 参阅 samber/cc-skills-golang@golang-uber-dig 技能,了解无生命周期管理的运行时反射型 DI
  • → 参阅 samber/cc-skills-golang@golang-uber-fx 技能,了解支持生命周期钩子、模块化及信号感知 Run() 的运行时 DI
  • → 参阅 samber/cc-skills-golang@golang-samber-do 技能,了解基于泛型、无需反射的 DI
  • → 参阅 samber/cc-skills-golang@golang-structs-interfaces 技能,了解接口设计模式
  • → 参阅 samber/cc-skills-golang@golang-testing 技能,了解通用测试模式

如在使用 google/wire 时遇到 Bug 或异常行为,请在 https://github.com/google/wire/issues 提交 Issue。

相关专题

更多
GORM框架数据模型设计教程
GORM框架数据模型设计教程

本专题讲解GORM框架数据模型设计方法,涵盖模型定义、字段标签、主键设置、自定义类型、Hook钩子、表名映射、字段映射与自动迁移等内容,帮助开发者掌握GORM框架模型设计技巧,实现数据库结构规范管理。

2026.08.13

300

16

GORM框架数据库操作详解
GORM框架数据库操作详解

本专题围绕GORM框架数据库操作展开,涵盖增删改查、CRUD操作、条件查询、分页排序、批量处理、事务操作及多数据库应用等内容,帮助开发者掌握GORM框架数据操作方法,提升Go语言数据库开发效率。

2026.08.13

200

13

GORM框架安装配置指南
GORM框架安装配置指南

本专题汇总GORM框架安装配置指南,涵盖GORM安装配置、环境搭建、数据库连接、多数据库支持、读写分离、连接池优化、事务处理及项目应用实践,帮助开发者掌握Go语言ORM框架使用方法,实现高效稳定的数据访问与管理。

2026.08.13

260

17

Kubernetes运维优化教程
Kubernetes运维优化教程

本专题总结Kubernetes运维优化实战经验,覆盖性能监控、指标告警、内存泄漏定位、网络延迟排查与成本优化,并演示Go语言性能剖析与调优手段,帮助运维开发协同提升集群与应用的稳定性和资源效率。

2026.08.13

140

14

Kubernetes云原生开发教程
Kubernetes云原生开发教程

本专题围绕Kubernetes云原生开发展开,涵盖Go语言集成、Docker部署、集群管理、微服务架构、client-go开发及CI/CD实践等内容,结合项目案例帮助开发者掌握容器编排、云原生应用开发与Kubernetes企业级实践能力。

2026.08.13

180

14

Kubernetes安装部署教程
Kubernetes安装部署教程

本专题系统整理Kubernetes安装部署全流程,涵盖kubeadm集群搭建、Golang环境配置、二进制部署、网络插件与存储对接,结合Go语言实战演示节点初始化与验证方法,帮助开发者从零搭建稳定可用的Kubernetes集群环境。

2026.08.13

160

14

Go语言微服务熔断降级与限流系统设计
Go语言微服务熔断降级与限流系统设计

本专题聚焦 Go 语言在微服务稳定性建设中的核心技术,讲解熔断机制、限流算法、服务降级策略以及分布式系统保护设计方法。通过实际架构案例,帮助开发者构建具备高可用与自我保护能力的后端服务系统。

2026.06.22

87

18

Go微服务与gRPC高性能通信实战
Go微服务与gRPC高性能通信实战

本专题围绕 Go 语言在微服务架构下的高性能通信实践展开,深入讲解 gRPC 协议、服务注册与发现、负载均衡、拦截器与性能调优策略。通过实战示例,帮助开发者构建高效可靠的分布式后端服务系统。

2026.04.27

718

17

Golang网络编程与高并发服务设计实践
Golang网络编程与高并发服务设计实践

本专题聚焦 Go 语言在高并发网络服务开发中的应用,讲解 TCP/HTTP 协议处理、Goroutine 调度、Channel 并发通信以及服务性能调优策略。通过实践案例,帮助开发者构建高性能、稳定可靠的后端服务系统。

2026.04.13

59

22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程