Wire概览
在讲解Kratos的过程中,我们引入了google推出的wire这个工具。我们先阅读一下官方的定义:
Wire is a code generation tool that automates connecting components using dependency injection.
从关键词入手:
- code generation 代码生成,一方面说明了有学习成本,需要了解这个工具的原理;另一方面,也说明了它的目标是消除重复性的coding
- automates connecting components 自动连接组件,明确了wire工具的目标是将多个对象组合起来
- dependency injection 依赖注入,指明了wire实现自动连接组件的思想。依赖注入是一个很强大的功能,我会在下面结合具体的case聊一聊
我们从具体的case着手,学习wire这个工具。
基本示例
常规实现
我简化了官方的示例,给出一个注释后的代码,方便大家阅读:
1 | package main |
这里的调用很直观,分为3步:
- 用
NewMessage
创建Message
对象 - 通过
NewGreeter
方法,将Message
对象注入到Greeter
对象里 - 调用
Greeter
的方法,其实内部用到了前面注入的Message
对象
依赖注入
依赖注入的详细定义可以参考链接 - https://en.wikipedia.org/wiki/Dependency_injection,我就不赘述了。这里我用具体的case进行对比,方便大家理解:
1 | type Greeter struct { |
看完例子,可能大家对DI已经有个初步的概念了,我这边再重复一下关键点:
Greeter
的方法Greet()
会依赖内部的Message
对象,所以我们说 - Greeter的实现依赖MessageMessage
的初始化分为两种:创建Greeter对象前和调用Greet方法时,前者被称为依赖注入,相当于在初始化时把依赖项注入进去,而不是使用时再创建。- DI,最直接的好处就是可以很方便地调整这个注入项,比如Greet升级成GreetV2,或者单测的MockGreet。
使用wire生成代码
我们先安装wire工具:
1 | go get github.com/google/wire/cmd/wire |
再编写一个wire.go
1 | //+build wireinject |
运行命令wire gen
生成wire_gen.go
1 | // Code generated by Wire. DO NOT EDIT. |
最后,可以在main
函数里使用
1 | func main() { |
wire的大致实现
可以看到,wire这个工具基本能力就体现在wire.Build(NewGreeter, NewMessage)
里,把这里面的两个初始化函数串联了起来,形成了一个整体的InitializeGreeter。
基本扩展
带error的处理
我们新增一个方法,初始化结果里增加一个error返回值:
1 | // Part-3 Greeter对象,依赖Message,并且返回error方法 |
然后在wire.go
里调整函数返回值增加一个error
1 | func InitializeGreeter() (Greeter, error) { |
最后,在wire_gen.go
里生成了带error的新方法
1 | func InitializeGreeterV2() (Greeter, error) { |
增加一个入参
我们新增一个方法,增加一个name的入参
1 | // Part-3 Greeter对象,依赖Message和参数name,并且返回error方法 |
wire.go
里也增加一个string
类型的入参(变量名可以任意)
1 | func InitializeGreeterV3(greetName string) (Greeter, error) { |
最后生成对应的方法
1 | func InitializeGreeterV3(greetName string) (Greeter, error) { |
Provider和Injector
Wire里面提了两个关键性的概念,为了方便大家阅读文档时能快速理解,我这里再专门说明下:
- Provider - 即各个初始化函数,如
NewXXX
- Injector - 即Initial的函数,将各个Provider注入到wire中,生成一个新的初始化函数
参考资料
Github - https://github.com/google/wire
DI - https://en.wikipedia.org/wiki/Dependency_injection
思考
wire
工具的实现逻辑很清晰 - 按一定规则组装多个Provider到Injector中。
生成的代码 结构简单而具有规律,所以用代码生成技术很有价值,既减少了重复性工作,又能引入DI的思想方便程序的扩展。
小结
至此,我们对wire的基础用法已经了然于胸,但更多的价值需要深入理解DI这个概念,最好能结合到具体的工程实践上。如果你对这块还没有太深刻的理解,建议结合网上的相关资料了解DI在工程中的价值,会让你使用wire这个工具时更有感触。
Github: https://github.com/Junedayday/code_reading
Blog: http://junes.tech/
Bilibili: https://space.bilibili.com/293775192
公众号: golangcoding