依赖注入是啥
首先,程序启动时,一般都要初始化好一批对象:将对象需要的依赖都注入进去。
当然,也有运行期间初始化的,不过提前初始化性能肯定更好。
有这么个需求:程序启动,需要初始化对象A,而对象A依赖对象B
最简单的注入方式:自己手动创建对象B,然后手动注入到对象A中。
痛点:当对象非常多、依赖关系非常复杂时,手动进行依赖注入及依赖管理肯定是非常折磨、低效的。
所以,有了自动依赖注入(交给程序)。
我们的期望:
假设有100个类或结构体,在程序启动时,我们需要初始化这100个实例,我们希望有这么一个东西:把这100个类或结构体丢给它,然后它能自动完成【初始化100个实例】的工作。
在Java的Spring框架中,Spring IOC容器负责进行依赖注入及依赖管理,我们只需要在类上加上@Component等注解就能将对象注册到IOC容器中,IOC容器就会帮助我们注入依赖、初始化对象。
那go的世界里有没有这玩意儿?
Wire就是干这活的。
go语言中有很多这样的工具
目的、作用
是一个依赖注入 工具,旨在简化初始化代码的管理。
特点
- 通过自动生成代码的方式在编译期完成依赖注入
如何注入
具体用法看官方文档,github地址
-
两个角色:
- Provider
- Injector
-
wire.go
文件 -
自动生成代码
wire_gen.go
1 创建Provider
本质是一个普通的go函数,负责创建对象(函数的返回值就是它要创建的对象),provider函数可以接收其他provider的返回值,从而形成了依赖注入。
经常一起使用的Provider可以组成Provider集合。一个Provider集合可以添加其他Provider集合。
2 创建Injector
本质是一个函数,会按依赖顺序调用Providers。
如何声明Injector?
- 声明一个函数。
- 函数body调用
wire.Build
,函数具体的返回值无关紧要,自动生成代码时会忽略它,只要返回值的类型正确即可。
实验:能否声明多个Injector?
3 编写 wire.go
4 自动生成代码
会生成wire_gen.go
文件,可以看看Injector的函数体,其实就是按依赖顺序调用Providers来创建实例。
高级特性
-
Provider的返回值类型可以是interface类型,而不用是一个具体类型。
-
...
参考
Demo
不使用wire时
不使用wire自动注入,想要创建结构体A的实例需要自己手动创建依赖、初始化结构体实例
package main
import "fmt"
type A struct {
B
s string
i int
}
type B struct {
C
strs []string
}
type C struct {
X, Y int
}
func newA(b *B) *A {
return &A{B: *b, s: string("hello"), i: 100}
}
func newB(c *C) *B {
return &B{C: *c, strs: []string{"i", "like", "apple"}}
}
func newC() *C {
return &C{
X: 1,
Y: 2,
}
}
// 不使用wire自动注入,如何创建结构体A的实例
func main() {
// 需要自己一个个手动创建依赖,然后初始化结构体A的实例
c := newC()
b := newB(c)
a := newA(b)
fmt.Printf("a: %v %p\n", a, a)
}
使用wire时
新建wire.go文件:
//go:build wireinject
// +build wireinject
package main
import (
"github.com/google/wire"
)
// newA、newB、newC就是Provider,InitA就是Injector
func InitA() *A {
wire.Build(newA, newB, newC)
return &A{}
}
然后在当前目录下执行wire
命令,就会自动生成wire_gen.go
:
可以看到自动生成的代码其实就是按依赖顺序调用provider来创建实例
// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
// Injectors from wire.go:
func InitA() *A {
c := newC()
b := newB(c)
a := newA(b)
return a
}