筆記二提過依賴注入,和如何生成,但沒有細講,本文來簡單看看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)), 能夠看到會找不到依賴。
