go依赖注入管理工具wire的使用方法
作者:小范真是一把好手
wire能做什么?
wire是一个依赖注入管理的工具。主要包含两个角色provider,injector,
- provider: a function that can produce a value.
- injector: a fucntion that calls providers in dependency order.
我们通过简单电子商务网站的例子来看看wire能干什么。假设有个购物车(ShoppingCart)的对象,该对象由多个产品列表(ProductList)组成,他们的UML关系如下
具体代码实现如下,
type ShoppingCart struct { // 依赖于产品列表 ProductList *ProductList // 其他属性和方法 } // 产品列表模块 type ProductList struct { // 一些产品数据和方法 } // 创建购物车的函数, 这就是依赖注入 // ShoppingCart对象,需要的部分组件,来自于入参,而不是函数内部构建 func NewShoppingCart(pl *ProductList) (*ShoppingCart, error) { return &ShoppingCart{ProductList: pl}, nil } // 创建产品列表的函数 func NewProductList() (*ProductList, error) { return &ProductList{}, nil }
在不使用wire的情况下,如果我们需要使用ShoppingCart
对象,需要下面这样一段初始化代码:
func InitializeShoppingCart() (*ShoppingCart, error) { // 1. 首先构建productList productList, err := NewProductList() if err != nil { return nil, err } // 2. 构建ShoppingCart shoppingCart, err := NewShoppingCart(productList) if err != nil { return nil, err } return shoppingCart, nil }
这个例子只涉及到两个对象,所以这段代码写起来不费力气。如果这是一个复杂的WebServer
对象呢?我们初始化较多的对象,比如redisDao,MySQLDao,Kafka,Log,httpServer,grpcServer
等等,这些依赖关系都需要我们自己处理,那得多麻烦啊。所以,wire就是解决这个问题的,你可以理解wire帮我们写了类似于InitializeShoppingCart 这个函数。 下面,我们来看看如何使用wire?
wire如何解放双手?
我们知道wire中有两个概念,一个是provider,一个是injector,在上面例子中,
- provider:是
NewShoppingCart, NewProductList
这两个函数
他们有一个共同点是,都创建一个对象。现在我们需要创建一个指令,告诉wire如何根据这些provider,写出InitializaShoppingCart
这个函数。我们想想,如果wire是一个人,你该如何告诉他写这个函数呢?
- 告诉他,这个函数,最终创建的对象是什么?也就是
return
是什么?【注,也有一些人这样写,传入的是指针,函数中所有的操作,就是初始化这个指针中的内容】 - 需要有哪些provider,能够创建最终的对象?
明白这两点,我们新建一个wire.go
的文件,并在开始处写上+build wireinjector
。接着,写上这样一段代码:
func InitializeShoppingCart() (*ShoppingCart, error) { wire.Build( NewShoppingCart, NewProductList, ) return nil, nil }
然后,在文件所在目录,执行wire
。这个时候,会出现一个wire_gen.go
的文件。
func InitializeShoppingCart() (*ShoppingCart, error) { productList, err := NewProductList() if err != nil { return nil, err } shoppingCart, err := NewShoppingCart(productList) if err != nil { return nil, err } return shoppingCart, nil }
wire生成的代码,和我们自己写的是一样的。相比于处理复杂的对象依赖关系,写一个injector
要简单的多。关于wire的使用,还是有一些坑的,下面我们看看如何避开这些坑。
注意事项
坑一:创建同一个对象,只需要一个provider,不要创建多个provider。
set has multiple bindings for go-tool/basic/wire1.Fooer
当injector中,有多个provider生成同一个对象时,会报上述错误。
坑二:当使用接口时,保证上provider生成的是接口,后一个provider使用的也是接口,同时保证1对1关系;
坑三:如果一个provider生成的是接口实现的结构体,另外一个是provider的入参是接口,这个时候,需要显式的使用wire.Bind
函数告诉接口的具体实现者。
var set = wire.NewSet(NewFooerImp, NewSecond, wire.Bind(new(Fooer), new(*MyFooer)))
坑四:提供的Provider需要刚刚好,不要多,也不要少;
- inject InitializeEvent: unused provider "NewEventNumber: 有没有使用过的provider;
- inject InitializeEvent: no provider found for Greet: 没有provider;
以上就是go依赖注入管理工具wire的使用方法的详细内容,更多关于go wire管理依赖的资料请关注脚本之家其它相关文章!