Wire 是一个灵活的依赖注入工具,通过自动生成代码的方式在编译期完成依赖注入。

在各个组件之间的依赖关系中,通常鼓励显式初始化,而不是全局变量传递。

所以通过 Wire 进行初始化代码,可以很好地解决组件之间的耦合,以及提高代码维护性。

安装工具

  1. go get github.com/google/wire/cmd/wire

工作原理

Wire 具有两个基本概念:ProviderInjector

Provider 是一个普通的 Go Func ,这个方法也可以接收其它 Provider 的返回值,从而形成了依赖注入;

  1. // 提供一个配置文件(也可能是配置文件)
  2. func NewConfig() *conf.Data {...}
  3. // 提供数据组件,依赖了数据配置(初始化 Database、Cache 等)
  4. func NewData(c *conf.Data) (*Data, error) {...}
  5. // 提供持久化组件,依赖数据组件(实现 CURD 持久化层)
  6. func NewUserRepo(d *data.Data) (*UserRepo, error) {...}

使用方式

在 Kratos 中,主要分为 server、service、biz、data 服务模块,会通过 Wire 进行模块顺序的初始化;

kratos ddd

在每个模块中,只需要一个 ProviderSet 提供者集合,就可以在 wire 中进行依赖注入;

并且我们在每个组件提供入口即可,不需要其它依赖,例如:

  1. -data
  2. --data.go // var ProviderSet = wire.NewSet(NewData, NewGreeterRepo)
  3. --greeter.go // func NewGreeterRepo(data *Data, logger log.Logger) biz.GreeterRepo {...}

然后通过 wire.go 中定义所有 ProviderSet 可以完成依赖注入配置。

初始化组件

通过 wire 初始化组件,需要定义对应的 wire.go,以及 kratos application 用于启动管理。

  1. // 应用程序入口
  2. cmd
  3. -main.go
  4. -wire.go
  5. -wire_gen.go
  6. // main.go 创建 kratos 应用生命周期管理
  7. func newApp(logger log.Logger, hs *http.Server, gs *grpc.Server, greeter *service.GreeterService) *kratos.App {
  8. pb.RegisterGreeterServer(gs, greeter)
  9. pb.RegisterGreeterHTTPServer(hs, greeter)
  10. return kratos.New(
  11. kratos.Name(Name),
  12. kratos.Version(Version),
  13. kratos.Logger(logger),
  14. kratos.Server(
  15. hs,
  16. gs,
  17. ),
  18. )
  19. }
  20. // wire.go 初始化模块
  21. func initApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, error) {
  22. // 构建所有模块中的 ProviderSet,用于生成 wire_gen.go 自动依赖注入文件
  23. panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp))
  24. }

在项目的 main 目录中,运行 go generate 进行生成编译期依赖注入代码:

  1. go generate ./...

References