wire

一、简单说明

wire,一个轻巧的golang依赖注入工具。是Go Cloud团队开发的工具包。

它只是一个代码生成器,并不是一个框架。

只需要在一个特殊的go文件中,声明wire类型之间的依赖关系,然后通过一个命令(wire),它就会自动帮我们生成代码,帮助我们创建指定类型的对象,并组装它的依赖。

 

二、问题抛出

如上,我们创建了3个类型Message、People、Student,我们想调用Say()方法时,需要将这三者组装起来:

在结构不复杂的情况下,上面的实现并不会有什么问题。当项目庞大到一定程度,结构之间的关系变得非常的复杂,这种情况下手动创建每个依赖,然后将它们组装起来,就会变得异常的繁琐,而且容易出错。

于是乎,wire就站出来了。

 

三、安装

该命令会在 $GOPATH/bin 中生成一个可执行文件wire

 

四、使用

wire的使用很简单,新建一个wire.go文件(文件名可以随意,建议和业务保持一致),创建初始化函数。例如,我们要创建并初始化一个Student对象,可以这样写:

在命令行执行wire,将会自动生成wire_gen.go。wire_gen.go内容如下:

我们发现,和我们上面main方法中自己编写的内容差不多。然后,在main方法中,使用InitializeStudent()来创建Student对象,并执行,发现效果也是一样的:

 

五、注意

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

 

六、相关概念

wire有两个核心概念,Provider(构造器)和Injector(注入器)。

Provider: 实际上就是创建函数,生成组件的普通方法。这些方法接收所需依赖作为参数,创建组件并将其返回。组件可以是对象或方法,或者其它任何类型。

Injector: 由wire自动生成的函数。函数内部会按根据依赖顺序调用相关privoder

其它概念

ProviderSet: 一组相关业务的privoder放到一起组织成ProviderSet,方便维护和切换。

cleanup: 若 provider 和 injector 函数有返回错误,那么wire会自动处理。除此以外,wire还有另一项自动处理能力:清理函数。清理函数以 func() 闭包的形式存在, 随provider生成的组件一起返回, 确保组件所需资源可以得到清理。