快速使用:
1.先安装工具
$ go get github.com/google/wire/cmd/wire
上述命令生成一个可执行程序wire,这就是代码生成器
2.简单使用
main.go
func NewMessage(msg string) Message {
return Message(msg)
}
type Message string
func NewGreeter(m Message) Greeter {
return Greeter{Message: m}
}
type Greeter struct {
Message Message
}
func (g Greeter) Greet() Message {
return g.Message
}
func NewEvent(g Greeter) Event {
return Event{Greeter: g}
}
type Event struct {
Greeter Greeter
}
func (e Event) Start() {
msg := e.Greeter.Greet()
fmt.Println(msg)
}
func main() {
event := InitializeEvent("hello_world")
event.Start()
}
wire.go
// +build wireinject
// The build tag makes sure the stub is not built in the final build.
package main
import (
"github.com/google/wire"
)
// InitializeEvent 声明injector的函数签名
func InitializeEvent(msg string) Event {
wire.Build(NewEvent, NewGreeter, NewMessage)
return Event{} //返回值没有实际意义,只需符合函数签名即可
}
// +build wireinject wire工具只会处理有wireinject的文件
执行命令 $wire 生成wire_gen.go文件
wire_gen.go
//+build !wireinject
package main
// Injectors from wire.go:
// InitializeEvent 声明injector的函数签名
func InitializeEvent(msg string) Event {
message := NewMessage(msg)
greeter := NewGreeter(message)
event := NewEvent(greeter)
return event
}
一些概念
provider(构造器)和injector(注入器)是wire的两个核心概念
通过提供provider函数,让wire知道如何产生这些依赖对象。wire根据我们定义的injector函数签名,生成完整的injector函数,injector函数是最终我们需要的函数,它将按依赖顺序调用provider。
provider就是普通的Go函数,可以把它看作是某对象的构造函数,我们通过provider告诉wire该对象的依赖情况
injector是wire生成的函数
高级特性
1.接口绑定
依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。核心思想是面向接口编程。
main.go
packahe main
// User
type User struct {
}
// UserService
type UserService struct {
userRepo UserRepository // <-- UserService依赖UserRepository接口
}
// UserRepository 存放User对象的数据仓库接口,比如可以是mysql,restful api ....
type UserRepository interface {
// GetUserByID 根据ID获取User, 如果找不到User返回对应错误信息
GetUserByID(id int) (*User, error)
}
// NewUserService *UserService构造函数
func NewUserService(userRepo UserRepository) *UserService {
return &UserService{
userRepo: userRepo,
}
}
// mockUserRepo 模拟一个UserRepository实现
type mockUserRepo struct {
foo string
bar int
}
// GetUserByID UserRepository接口实现
func (u *mockUserRepo) GetUserByID(id int) (*User, error) {
return &User{}, nil
}
// NewMockUserRepo *mockUserRepo构造函数
func NewMockUserRepo(foo string, bar int) *mockUserRepo {
return &mockUserRepo{
foo: foo,
bar: bar,
}
}
func main() {
userService := InitializeUserService("foo", 100)
_ = userService
}
wire.go
// +build wireinject
// The build tag makes sure the stub is not built in the final build.
package main
// MockUserRepoSet 将 *mockUserRepo与UserRepository绑定
var MockUserRepoSet = wire.NewSet(NewMockUserRepo, wire.Bind(new(UserRepository), new(*mockUserRepo)))
func InitializeUserService(foo string, bar int) *UserService {
wire.Build(NewUserService, MockUserRepoSet) // 使用MockUserRepoSet
return nil
}
不进行绑定时,执行命令$ wire
wire: src\zpool\wire.go:24:1: inject InitializeUserService: no provider found for zpool.UserRepository needed by *zpool.UserService in provider "NewUserService" (src\zpool\main.go:84:6) wire: zpool: generate failed wire: at least one generate failure
wire_gen.go
func InitializeUserService(foo string, bar int) *UserService {
mainMockUserRepo := NewMockUserRepo(foo, bar)
userService := NewUserService(mainMockUserRepo)
return userService
}
2.结构体provider
除了函数外,结构体也可以充当provider的角色
main.go
type Foo int
type Bar int
func ProvideFoo() Foo {
return 1
}
func ProvideBar() Bar {
return 2
}
type FooBar struct {
MyFoo Foo
MyBar Bar
}
wire.go
// +build wireinject
package main
var Set = wire.NewSet(
ProvideFoo,
ProvideBar,
wire.Struct(new(FooBar), "MyFoo", "MyBar"))
func InitializeFooBar() FooBar {
wire.Build(Set)
return FooBar{}
}
wire_gen.go
func InitializeFooBar() FooBar {
foo := ProvideFoo()
bar := ProvideBar()
fooBar := FooBar{
MyFoo: foo,
MyBar: bar,
}
return fooBar
}