Go mod 好菜系列 - 0x0B wire 这口依赖注入别硬吞
详细聊 wire 是来解决什么的、为什么 Go 项目会谈依赖注入、它适合什么规模,以及什么时候完全没必要把项目搞成装配迷宫。
只要项目开始长出 service、repository、client、config、logger 这些层次,迟早就会有人提出一个词:依赖注入。很多人一听到这个词就条件反射想到 Java 式的大框架,然后开始精神紧张。Go 里的 wire 比那种动态容器路线克制很多,但它依然值得你先想清楚:你到底需不需要它。
wire 是解决什么的
它不是运行时魔法容器,而是一个 编译期依赖注入代码生成工具。通俗说,就是你把“这些对象怎么拼起来”描述给它,它帮你生成那段装配代码。
为什么会出现这种需求
看一个很常见的项目装配过程:
cfg := LoadConfig()
logger := NewLogger(cfg)
db := NewDB(cfg)
repo := NewUserRepo(db)
svc := NewUserService(repo, logger)
handler := NewUserHandler(svc)这段代码本身没什么错。但当项目组件越来越多、初始化依赖越来越深的时候,这段“组装流程”会越来越长,越来越散。wire 就是想把这件事收拢起来。
wire 的基本感觉
func InitializeUserHandler() (*UserHandler, error) {
wire.Build(
NewConfig,
NewLogger,
NewDB,
NewUserRepo,
NewUserService,
NewUserHandler,
)
return nil, nil
}然后 wire 会生成真正的初始化代码。也就是说,你不是把依赖关系藏进黑盒,而是把它显式描述出来,再交给工具展开。
它最大的优点是什么
- 依赖关系显式
- 编译期生成,不靠运行时反射
- 大项目里装配层更整洁
- 比手写一大堆工厂函数更容易统一管理
如果你项目真开始变复杂,这种“把装配层单独对待”的思路会越来越有价值。
但它不是所有项目的必需品
很重要的一句:如果你的项目现在只有三层、五个对象、十个构造函数,那大概率根本没必要上 wire。
很多人会在项目还没复杂到那个地步时,先引入一套依赖注入工具,结果最后最大的复杂度来自“我为了用工具而写了更多装配代码”。
wire 最适合什么场景
- 服务组件很多
- 初始化链条长
- 多个模块共享一套依赖装配规则
- 团队希望入口装配更统一
它更像是一种“项目规模长大以后降低混乱”的手段,不是小项目起手必备套餐。
小结
wire 这道菜很看项目体量:
- 它解决的是依赖装配复杂度,不是业务复杂度
- 编译期生成比运行时容器更克制
- 项目足够大时很有帮助
- 项目还小时,手写初始化往往更直接
下一篇我们讲 fx。它也是装配和生命周期这条线上的选手,但思路和 wire 不太一样。