1.简介

A a = new A()

wire就是一个实现依赖注入的工具,不同之处在于: wire不是在运行时通过反射动态地进行依赖注入,而是在编译期通过静态代码生成的方式达成这个目的。

.go

2.两个概念

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.Bind
var set = wire.NewSet(NewTypeA, 
NewTypeB, 
wire.Bind(new(ITypeA), new(*TypeA)))

func Inject() *TypeB {
    wire.Build(set)
    return &TypeB{}
}

3.2 构造结构体

wire.Struct
type 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.Value
type 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.FieldsOf
type 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.Build

4. 总结

wire通过代码生成的方式实现依赖注入,这依赖于两个很重要的概念,即Provider和Injector。

可以理解为:

  1. Provider用于提供依赖注入过程中需要的对象,它将所有的对象放到一个大池子里面,供Injector使用;
  2. Injector能够根据各个对象的依赖关系,将池子中的对象组合起来,根据Inject函数(即调用wire.Build函数的函数)的返回值决定将池子中哪个对象(或对象的字段)返回出来