写点什么

Go 依赖注入 Wire 详解 - 用户指南

作者:baiyutang
  • 2022 年 5 月 22 日
  • 本文字数:1398 字

    阅读完需:约 5 分钟

Wire 有两个核心概念:providers 和 injectors。

Provider

Wire 的主要机制是 provider:能够生成值的函数。这些函数是普通的 Go 代码。

package foobarbaz
type Foo struct { X int}
// ProvideFoo returns a Foo.func ProvideFoo() Foo { return Foo{X: 42}}
复制代码


Provider 函数必须能被导出,为了能被其他包使用,就像普通函数一样。


Provider 可以用参数指定依赖关系:

package foobarbaz
// ...
type Bar struct { X int}
// ProvideBar returns a Bar: a negative Foo.func ProvideBar(foo Foo) Bar { return Bar{X: -foo.X}}
复制代码


Provider 也可以返回 error:

package foobarbaz
import ( "context" "errors")
// ...
type Baz struct { X int}
// ProvideBaz returns a value if Bar is not zero.func ProvideBaz(ctx context.Context, bar Bar) (Baz, error) { if bar.X == 0 { return Baz{}, errors.New("cannot provide baz when bar is zero") } return Baz{X: bar.X}, nil}
复制代码


Provider 可以被分组成 provider sets。如果要经常同时使用多个提供程序,这是很有用的。要将这些 Provider 添加到名为 SuperSet 的集合,使用 wire.NewSet 函数:

package foobarbaz
import ( // ... "github.com/google/wire")
// ...
var SuperSet = wire.NewSet(ProvideFoo, ProvideBar, ProvideBaz)
复制代码


你也可以添加其他 provider setprovider set 中。

package foobarbaz
import ( // ... "example.com/some/other/pkg")
// ...
var MegaSet = wire.NewSet(SuperSet, pkg.OtherSet)
复制代码

Injector

应用程序用 injector 将这些 providers 连接起来:injector 是一个按依赖顺序调用 providers 的函数。使用 Wire,你写 injector 的签名,然后 Wire 生成函数体。

// +build wireinject// The build tag makes sure the stub is not built in the final build.
package main
import ( "context"
"github.com/google/wire" "example.com/foobarbaz")
func initializeBaz(ctx context.Context) (foobarbaz.Baz, error) { wire.Build(foobarbaz.MegaSet) return foobarbaz.Baz{}, nil}
复制代码


injector 可以像 providers 一样在输入上参数化和返回 error。wire.Build 的参数和 wire.NewSet 一样:他们来自一个 provider set


任何在带有 injector 的文件中发现的非注入器声明都会被复制到生成的文件中。


你可以通过在包目录中调用 Wire 来生成 injector

wire
复制代码


Wire 会生成 injector 的实现到一个名为 wire_gen.go 文件,如下:

// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire//+build !wireinject
package main
import ( "example.com/foobarbaz")
func initializeBaz(ctx context.Context) (foobarbaz.Baz, error) { foo := foobarbaz.ProvideFoo() bar := foobarbaz.ProvideBar(foo) baz, err := foobarbaz.ProvideBaz(ctx, bar) if err != nil { return foobarbaz.Baz{}, err } return baz, nil}
复制代码


正如您所看到的,输出非常接近开发人员自己编写的内容。此外,它在运行时几乎不依赖于 Wire:所有编写的代码都是普通的 Go 代码,不需要 Wire 也可以使用。


一旦创建了 wire_gen.go , 你也可以运行 go generate 重新生成。


参考


发布于: 刚刚阅读数: 5
用户头像

baiyutang

关注

广州 2017.12.13 加入

Microservices | Golang | Cloud Nitive | “Smart work,Not hard”

评论

发布
暂无评论
Go 依赖注入 Wire 详解 - 用户指南_Go_baiyutang_InfoQ写作社区