一、介绍

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代码的依赖注入,它自动帮我们注入参数!

谢谢您的观看,欢迎关注我的公众号。

image.png


海生
104 声望34 粉丝

与黑夜里,追求那一抹萤火。