Wire 的 provider 集合必须按依赖方向分层声明,正确做法是将 data、service、server 各层 ProviderSet 显式拆分并按顺序组合;子模块需独立 wire.go;跨模块调用须经 biz 接口;proto 修改后须同步 go generate。

Wire 的 provider 集合必须按依赖方向分层声明
Wire 不会自动推导依赖顺序,ProviderSet 里如果把 data.NewUserRepo 和 service.NewUserService 放在同一个集合里,且 NewUserService 构造函数依赖 userRepo 接口,但 NewUserRepo 实现没被提前注入,就会编译失败报 “missing type” 或 “no provider found for …”。
正确做法是显式拆成两组:
-
data.ProviderSet:只包含data.NewUserRepo、data.NewOrderRepo等数据层 provider -
service.ProviderSet:接收biz.UserRepo等接口为参数,不 importdata包 - 顶层
AppProviderSet按依赖顺序组合:data.ProviderSet→service.ProviderSet→server.ProviderSet
子模块的 wire.go 必须独立生成,不能全堆在 cmd/server/wire.go 里
当业务膨胀到有 user、order、payment 多个子域时,硬把所有 provider 全塞进一个 wire.go 会导致三个问题:编译慢、冲突多、无法按需启用模块。比如 payment 模块依赖第三方支付 SDK,但 user 模块完全不需要它。
推荐结构:
-
internal/user/wire.go:定义UserProviderSet,只拉internal/user/biz和internal/user/data -
internal/order/wire.go:同理,OrderProviderSet独立维护 -
cmd/server/wire.go只做组装:user.UserProviderSet、order.OrderProviderSet、payment.PaymentProviderSet按需导入
这样改了 user 模块,go generate ./ 只重生成 user 相关部分,不会触发整个服务重建。
跨子模块调用必须通过 biz 层接口,禁止 data 层直连
常见错误是 order 模块需要查用户昵称,直接在 internal/order/data 里 import internal/user/data,导致循环依赖或模块耦合。Wire 会报错 “import cycle not allowed”。
正确路径是:
-
internal/user/biz定义type UserRepo interface { GetByID(ctx context.Context, id string) (*User, error) } -
internal/user/data实现该接口,不暴露 struct -
internal/order/service的构造函数接收biz.UserRepo参数(来自user.UserProviderSet) -
cmd/server/wire.go把user.NewUserRepo()注入给order.NewOrderService()
这样 order 模块完全不知道 user 数据怎么存,只依赖契约;未来 user 换成 Redis 或 ES,order 层零修改。
Wire 生成失败时优先检查 proto 修改与 go generate 同步性
很多团队在加新字段到 api/user/v1/user.proto 后,忘记运行 go generate ./,结果 internal/user/biz.User 还是旧结构,而 internal/user/service 已经在用新字段,Wire 编译时报 “cannot use … as … value in argument to …” —— 表面是类型不匹配,根因是 pb 结构体没更新。
排查步骤:
- 确认
api/user/v1/user.pb.go中结构体字段已更新 - 确认
internal/user/biz.ToDomainUser()映射函数已适配新字段(如果用了映射层) - 确认
internal/user/data里数据库查询逻辑是否漏字段(如 GORM Scan 或 sqlx.QueryRow) - 最后再跑
go generate ./,不是只跑wire
Wire 本身不感知 proto,但它生成的代码会引用 pb 和 biz 类型,三者不同步是高频卡点。











