一、介绍
wire是提供go的依赖注入
官方包地址为 https://github.com/google/wire
我们打开官方ur,安装方式如下
go install github.com/google/wire/cmd/wire
安装后,就有wire命令可以用了,我试试在命令行工具里,输入wire
➜ wire
输出:
wire: -: no Go files /Users/zhanghaisheng/study/dataStructure/wirewire: generate failed
wire: generate failed
我们查看wire命令支持哪些参数,在命令行工具里,输入 wire help
➜ wire help
输出:
Usage: wire <flags> <subcommand> <subcommand args>
Subcommands:
check print any Wire errors found
commands list all command names
diff output a diff between existing wire_gen.go files and what gen would generate
flags describe all known top-level flags
gen generate the wire_gen.go file for each package
help describe subcommands and their syntax
show describe all top-level provider sets
Use "wire flags" for a list of top-level flags
可以看到wire支持的命令
二、入门案例:controller,service,model 为例子。
在一个web服务,我们会把路由映射到controller的方法上,这里简单建立一个 controller。
我们在一个学习的目录下建立下面4个空文件
.
├── user_controller.go //controller文件
├── user_model.go //model 以及数据库操作文件
├── user_service.go //user相关的逻辑
└── user_test.go //test测试用例文件
user_model.go文件为数据结构model,我们打开写入以下内容:
type UserModel struct {
Name string
Age int
}
func NewUserModel() UserModel {
return UserModel{Name: "hi", Age: 10}
}
user_service.go文件为user服务类,我们在里面写一些操作user的逻辑。打开文件,写入以下内容:
type UserService struct {
userModel UserModel
}
func NewUserService(user UserModel) UserService {
return UserService{
userModel: user,
}
}
func (s UserService) GetName() string {
return s.userModel.Name
}
UserService 结构体里面,有属性字段userModel,这个在我们NewUserService()的时候,以参数传进来。
user_controller.go文件为controller类,我们在这里处理一些用户参数,以及调度不同的service,打开写入以下内容:
type UserController struct {
userService UserService
}
func NewUserController(userService UserService) UserController {
return UserController{
userService: userService,
}
}
func (c UserController) GetName() string {
return c.userService.GetName()
}
三、传统的初始化对象方式
3.1、 初始化UserModel
我们在 user_test.go 里输入如下代码:
func TestModel(t *testing.T) {
md := NewUserModel()
t.Log(md)
}
我们使用的时候,NewUserModel(),没有传参,是最简单的new
3.2、 初始化UserService
我们在 user_test.go 里输入如下代码:
func TestService(t *testing.T) {
service := NewUserService(NewUserModel())
t.Log(service.GetName())
}
我们使用 NewUserService(NewUserModel()) 初始化 UserService对象。
3.3、 初始化UserController
我们在 user_test.go 里输入如下代码:
func TestController(t *testing.T) {
c := NewUserController(NewUserService(NewUserModel()))
t.Log(c.GetName())
}
我们使用 NewUserController(NewUserService(NewUserModel())) 初始化 UserController对象。
3.4 这种方式有什么问题?
这几种方式我们都是以对象注入的方式,初始化对象,对于一个controler,目前只有一个属性字段userService,如果有4,5个会怎么样,那么这个初始化就会变的非常长!比如下面这样
NewUserController(NewUserService(NewUserModel()),NewRedisService(NewUserModel()),NewCacheService(NewUserModel()))
有没有更好的方案?
有,依赖注入,wire库。
四、使用wire依赖注入
我们新建一个同级目录 wireinject如下
.
├── user_controller.go
├── user_model.go
├── user_service.go
├── user_test.go
└── wireinject
然后执行
➜ cd wireinject
在wireinject下面,新建一个 wire.go 文件,初始代码如下:
//go:build wireinject
// +build wireinject
package wireinject
4.1 初始化UserModel
我们在 wire.go 输入
func NewUserModel() demo.UserModel {
panic(
wire.Build(
demo.NewUserModel,
))
}
然后执行
➜ wire
会发现 wireinject 目录下,多了一个文件 wire_gen.go
.
├── wire.go
└── wire_gen.go
这个为wire命令生成
4.2、 初始化UserService
我们在 wire.go 里输入如下代码:
func NewUserService() demo.UserService {
panic(
wire.Build(
demo.NewUserModel,
demo.NewUserService,
))
}
我们使用 NewUserService() 初始化 UserService对象。return返回值为 demo.UserService对象,在函数里用panic包裹
wire.build(....),其中wire.build为我们要依赖注入的函数,把注入到这个函数里,然后自动的生成对象,这里参数是 demo.NewUserModel,demo.NewUserService,
为里面需要初始化的对象。
然后执行
➜ wire
4.3、 初始化UserController
我们在 wire.go 里输入如下代码:
func NewUserController() demo.UserController {
panic(
wire.Build(
demo.NewUserModel,
demo.NewUserService,
demo.NewUserController,
))
}
然后执行
➜ wire
4.4 使用
我们在 wireinject 目录下新建 wire_test.go并输入代码:
package wireinject
import "testing"
func TestModel(t *testing.T) {
md := NewUserModel()
t.Log(md)
}
func TestService(t *testing.T) {
service := NewUserService()
t.Log(service.GetName())
}
func TestController(t *testing.T) {
c := NewUserController()
t.Log(c.GetName())
}
此时发现我们并不需要输入参数了!这就是wire代码的依赖注入,它自动帮我们注入参数!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。