go微服务框架kratos学习笔记八(kratos的依赖注入)

笔记二提过依赖注入,和如何生成,但没有细讲,本文来简单看看kratos的依赖注入。

什么是依赖注入

先来看一个小程序,

我们将创建三个结构类型:

type Message string

type Greeter struct {
// ... TBD
} type Event struct {
// ... TBD
}
Message
func NewMessage() Message {
return Message("Hi there!")
}
GreeterGreeter
func NewGreeter(m Message) Greeter {
return Greeter{Message: m}
} type Greeter struct {
Message Message // <- adding a Message field
}
MessageGreeterGreeterGreetMessage
func (g Greeter) Greet() Message {
return g.Message
}
EventGreeter
func NewEvent(g Greeter) Event {
return Event{Greeter: g}
} type Event struct {
Greeter Greeter // <- adding a Greeter field
}
Start()
func (e Event) Start() {
msg := e.Greeter.Greet()
fmt.Println(msg)
}
Startgreeter

现在我们小程序所有的组件就绪了,看看它是如何初始化所有组件的,它看起来可能是这样的

func main() {
message := NewMessage()
greeter := NewGreeter(message)
event := NewEvent(greeter) event.Start()
}
messagemessagegreetergreeterevent

这其实就是依赖注入dependency injection简称di的原理,

依赖注入能让测试变的更为简单,我们可以通过构造函数来进行注入。

SomeClass() has its constructor as following:

public SomeClass() {
myObject = Factory.getObject();
}
myObjectSomeClassmyObjectFactory
myObject
public SomeClass (MyClass myObject) {
this.myObject = myObject;
}
myObject

可以通过多种方式将依赖项注入到对象中(例如构造函数注入或setter注入)。甚至可以使用专门的依赖项注入框架(例如Spring)来做到这一点,但是肯定不是必需的。不需要那些框架的依赖注入。显式实例化和传递对象(依赖项)与框架注入一样好。

google wire

kratos 使用的 google wire 就是golang的一个依赖注入解决的工具,这个工具能够自动生成类的依赖关系。

依赖注入的一个缺点就是需要如此多的初始化步骤,让我们看看如何使用Wire来让初始化我们的组件变的更快.

将我们的小程序main函数改成如下形式:

func main() {
e := InitializeEvent() e.Start()
}
InitializeEvent
// wire.go

func InitializeEvent() Event {
wire.Build(NewEvent, NewGreeter, NewMessage)
return Event{}
}
 wire.BuildWireproviders
EventEventproviders Event
InitializeEvent

然后在wire.go目录下运行wire工具。

安装
WireInitializeEvent
// wire_gen.go

func InitializeEvent() Event {
message := NewMessage()
greeter := NewGreeter(message)
event := NewEvent(greeter)
return event
}

这看上去就像我们上面手工写的代码,想象一下,对于复杂得多的组件,Wire是多么有用。

kratos中的wire

最后回来看看kratos中的wire.go

// +build wireinject
// The build tag makes sure the stub is not built in the final build. package di import (
pb "demo/api"
"demo/internal/dao"
"demo/internal/server/grpc"
"demo/internal/server/http"
"demo/internal/service" "github.com/google/wire"
) var daoProvider = wire.NewSet(dao.New, dao.NewDB, dao.NewRedis, dao.NewMC)
var serviceProvider = wire.NewSet(service.New, wire.Bind(new(pb.DemoServer), new(*service.Service))) func InitApp() (*App, func(), error) {
panic(wire.Build(daoProvider, serviceProvider, http.New, grpc.New, NewApp))
}
wire.NewSetwire.Bind

wire.NewSet

WireProviders injectors
Providers
Providers 
Providers provider setswire.NewSet providers 
var daoProvider = wire.NewSet(dao.New, dao.NewDB, dao.NewRedis, dao.NewMC)
provider setsprovider sets
var MegaSet = wire.NewSet(daoProvider, pkg.OtherSet)
injector(注入器)
injectorprovidersproviders
wire.Build
func InitApp() (*App, func(), error) {
panic(wire.Build(daoProvider, serviceProvider, http.New, grpc.New, NewApp))
}

Binding Interfaces

wire.Bind
var serviceProvider = wire.NewSet(service.New, wire.Bind(new(pb.DemoServer), new(*service.Service)))

wire.Bind第一个参数 为指向所需接口类型的指针,第二个参数为 指向实现该接口类型的指针,

可以看到如果不加wire.Bind(new(pb.DemoServer), new(*service.Service)), 可以看到会找不到依赖。