1.简介
A a = new A()wire就是一个实现依赖注入的工具,不同之处在于: wire不是在运行时通过反射动态地进行依赖注入,而是在编译期通过静态代码生成的方式达成这个目的。
.go2.两个概念
wire中有两个很重要的概念: Provider和Injector。
2.1 Provider
NewXXX()使用时遵守一些简单的规则即可:
wire.NewSet()例如:
package main
type TypeA struct {
B *TypeB
}
type TypeB struct {}
func NewTypeA(b *TypeB) *TypeA{
return &TypeA{B: b,}
}
func NewTypeB() *TypeB{
return &TypeB{}
}2.2 Injector
上述Provider只是一个简单的生成对象的函数,它告诉应用程序在需要某些对象时应该如何获取。但为了实现依赖注入,程序还需要知道何时使用这些Provider函数以及各个Provider函数之间的调用顺序,这就需要Injector来发挥作用。
Injector实际就是一个能够根据各个组件的依赖关系按顺序调用Provider的函数。下面是一个简单的Injector声明。
// +build wireinject
package main
func Inject() *TypeA {
wire.Build(NewTypeA, NewTypeB)
return &TypeA{}
}需要注意的点:
// +build wireinjectwire.Buildwire下面是上述案例生成的Inject函数体:
func Inject() *TypeA {
typeB := NewTypeB()
typeA := NewTypeA(typeB)
return typeA
}3.高级特性
3.1 接口绑定
有时候为了便于拓展,我们会希望基于接口编程。比如将参数声明为某个接口类型,但是提供具体类型的构造函数,wire对这种场景提供了支持。
wire.NewSetwire.Bindvar set = wire.NewSet(NewTypeA,
NewTypeB,
wire.Bind(new(ITypeA), new(*TypeA)))
func Inject() *TypeB {
wire.Build(set)
return &TypeB{}
}3.2 构造结构体
wire.Structtype Foo int
type Bar int
func ProvideFoo() Foo {
return Foo(0)
}
func ProvideBar() Bar {
return Bar(0)
}
type FooBar struct {
MyFoo Foo
MyBar Bar
}
var Set = wire.NewSet(
ProvideFoo,
ProvideBar,
wire.Struct(new(FooBar), "MyFoo", "MyBar"))
func Inject() FooBar {
wire.Build(Set)
return FooBar{}
}*wire.Struct(new(FooBar), "*"))wire:"-"3.3 值绑定
wire.Valuetype Foo struct {
X int
}
func Inject() Foo {
wire.Build(wire.Value(Foo{X: 42}))
return Foo{}
}3.4 获取结构体的值
有时候我们希望能够将结构体的某些字段提供出去。一般情况下,为了达到这个目的,可以先获取到该结构体,然后调用对应的GetXXX方法(或者直接访问字段),但是这样我们得实现Get方法。
type Foo struct {
S string
N int
F float64
}
func getS(foo Foo) string {
// Bad! Use wire.FieldsOf instead.
return foo.S
}
func provideFoo() Foo {
return Foo{S: "Hello, World!", N: 1, F: 3.14}
}
func injectedMessage() string {
wire.Build(
provideFoo,
getS)
return ""
}wire.FieldsOftype Foo struct {
S string
N int
F float64
}
func provideFoo() Foo {
return Foo{S: "Hello, World!", N: 1, F: 3.14}
}
func injectedMessage() string {
wire.Build(
provideFoo,
wire.FieldsOf(new(Foo), "S"))
return ""
}3.5 一个使用Injector的小技巧
wire.Build4. 总结
wire通过代码生成的方式实现依赖注入,这依赖于两个很重要的概念,即Provider和Injector。
可以理解为:
- Provider用于提供依赖注入过程中需要的对象,它将所有的对象放到一个大池子里面,供Injector使用;
- Injector能够根据各个对象的依赖关系,将池子中的对象组合起来,根据Inject函数(即调用wire.Build函数的函数)的返回值决定将池子中哪个对象(或对象的字段)返回出来