wire,一个轻巧的golang依赖注入工具。是Go Cloud团队开发的工具包。
它只是一个代码生成器,并不是一个框架。
只需要在一个特殊的go文件中,声明wire类型之间的依赖关系,然后通过一个命令(wire),它就会自动帮我们生成代码,帮助我们创建指定类型的对象,并组装它的依赖。
xxxxxxxxxx
301// main.go
2
3package main
4
5type Message string
6func NewMessage(msg string) Message {
7 return Message(msg)
8}
9
10type People struct {
11 Message Message
12}
13func NewPeople(message Message) People {
14 return People{
15 Message: message,
16 }
17}
18
19type Student struct {
20 People People
21}
22func NewStudent(people People) Student {
23 return Student{
24 People: people,
25 }
26}
27func (s Student)Say() {
28 msg := s.People.Message
29 fmt.Println(msg)
30}
如上,我们创建了3个类型Message、People、Student,我们想调用Say()方法时,需要将这三者组装起来:
xxxxxxxxxx
101// main.go
2
3func main() {
4 msg := "hello world"
5 message := NewMessage(msg)
6 people := NewPeople(message)
7 student := NewStudent(people)
8
9 student.Say()
10}
在结构不复杂的情况下,上面的实现并不会有什么问题。当项目庞大到一定程度,结构之间的关系变得非常的复杂,这种情况下手动创建每个依赖,然后将它们组装起来,就会变得异常的繁琐,而且容易出错。
于是乎,wire就站出来了。
xxxxxxxxxx
11$ go get github.com/google/wire/cmd/wire
该命令会在 $GOPATH/bin 中生成一个可执行文件wire。
wire的使用很简单,新建一个wire.go文件(文件名可以随意,建议和业务保持一致),创建初始化函数。例如,我们要创建并初始化一个Student对象,可以这样写:
xxxxxxxxxx
121// student_wire.go
2
3// +build wireinject
4
5package main
6
7import "github.com/google/wire"
8
9func InitializeStudent(msg string) Student {
10 wire.Build(NewMessage, NewPeople, NewStudent)
11 return Student{}
12}
在命令行执行wire,将会自动生成wire_gen.go。wire_gen.go内容如下:
xxxxxxxxxx
151// Code generated by Wire. DO NOT EDIT.
2
3//go:generate go run github.com/google/wire/cmd/wire
4//+build !wireinject
5
6package main
7
8// Injectors from student_wire.go:
9
10func InitializeStudent(msg string) Student {
11 message := NewMessage(msg)
12 people := NewPeople(message)
13 student := NewStudent(people)
14 return student
15}
我们发现,和我们上面main方法中自己编写的内容差不多。然后,在main方法中,使用InitializeStudent()来创建Student对象,并执行,发现效果也是一样的:
xxxxxxxxxx
51func main() {
2 msg := "hello world"
3 student := InitializeStudent(msg)
4 student.Say()
5}
student_wire.go和生成的wire_gen.go,头部都有一个 +build,一个后面是wireinject,另一个却是!wireinject。
这是Go语言的一个特性,类似于C语言的条件编译。在执行go build时根据这个选项决定文件是否编译。
wire命令只会处理有wireinject的文件,所以student_wire.go头部需要带上 +build wireinject ;而生成的wire_gen.go是真正给程序使用的,所以设置为 +build !wireinject。
另:
1、Goland编辑器出现了InitializeStudent()重定义,需要在goland里设置build tag,设置 -> Go -> Build Tag & Vendoring,在custom tags里填入wireinject,保存即可。
2、同一个包下现在有两个文件,这两个文件里都有InitializeStudent()方法,所以我们不能用 go run main.go
运行程序,可以用 go run .
运行。或者用 go run main.go wire_gen.go
。
Provider: 实际上就是创建函数,生成组件的普通方法。这些方法接收所需依赖作为参数,创建组件并将其返回。组件可以是对象或方法,或者其它任何类型。
Injector: 由wire自动生成的函数。函数内部会按根据依赖顺序调用相关privoder。
ProviderSet: 一组相关业务的privoder放到一起组织成ProviderSet,方便维护和切换。
cleanup: 若 provider 和 injector 函数有返回错误,那么wire会自动处理。除此以外,wire还有另一项自动处理能力:清理函数。清理函数以 func() 闭包的形式存在, 随provider生成的组件一起返回, 确保组件所需资源可以得到清理。