笔记二提过依赖注入,和如何生成,但没有细讲,本文来简单看看kratos的依赖注入。github
什么是依赖注入
先来看一个小程序,golang
建立一个小程序模拟迎宾员问候客人的事件小程序
咱们将建立三个结构类型:api
1)为迎宾员建立消息 message
2)表达消息的迎宾员 greeter
3)迎宾员问候客人的事件 event网络
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
EventEventprovidersEvent
InitializeEvent
而后在wire.go目录下运行wire工具。
安装
go get github.com/google/wire/cmd/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
WireProvidersinjectors
Providers
Providers
Providersprovider setswire.NewSetproviders
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)), 能够看到会找不到依赖。