golang依赖注入wire包如何使用?
难题
针对golang对象难以管理,代码重复率高,耦合度高,应该如何解决?
什么是wire?
wire是一种依赖注入工具,通过构造器进行注入(暴露NewXXX等相关方法进行注入)类似,java构造器注入。
安装
go get github.com/google/wire/cmd/wire
Provider
生成组件的普通方法。这些方法接收所需依赖作为参数,创建组件并将其返回。
Injector
由`wire`自动生成的函数。函数内部会按根据依赖顺序调用相关 privoder 。
使用示例
这个 build tag 确保在常规编译时忽略 wire.go 文件(因为常规编译时不会指定
wireinject
标签)。 与之相对的是 wire_gen.go 中的//***+build*** !wireinject
。两组对立的 build tag 保证在任意情况下, wire.go 与 wire_gen.go 只有一个文件生效, 避免了“诸多相同的方法被重复定义”的编译错误
- wire.go
// +build wireinject
// The build tag makes sure the stub is not built in the final build.
package di
import (
"kratos_demo/internal/dao"
"kratos_demo/internal/service"
"kratos_demo/internal/server/grpc"
"kratos_demo/internal/server/http"
"github.com/google/wire"
)
//go:generate kratos t wire
func InitApp() (*App, func(), error) {
panic(wire.Build(dao.Provider, service.Provider, http.New, grpc.New, NewApp))
}
- wire_gen.go
这个文件不需要编辑和额外的关注。通过wire自动生成。
// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire
//+build !wireinject
package di
import (
"kratos_demo/internal/dao"
"kratos_demo/internal/server/grpc"
"kratos_demo/internal/server/http"
"kratos_demo/internal/service"
)
// Injectors from wire.go:
//go:generate kratos t wire
func InitApp() (*App, func(), error) {
redis, cleanup, err := dao.NewRedis()
if err != nil {
return nil, nil, err
}
memcache, cleanup2, err := dao.NewMC()
if err != nil {
cleanup()
return nil, nil, err
}
db, cleanup3, err := dao.NewDB()
if err != nil {
cleanup2()
cleanup()
return nil, nil, err
}
daoDao, cleanup4, err := dao.New(redis, memcache, db)
if err != nil {
cleanup3()
cleanup2()
cleanup()
return nil, nil, err
}
serviceService, cleanup5, err := service.New(daoDao)
if err != nil {
cleanup4()
cleanup3()
cleanup2()
cleanup()
return nil, nil, err
}
engine, err := http.New(serviceService)
if err != nil {
cleanup5()
cleanup4()
cleanup3()
cleanup2()
cleanup()
return nil, nil, err
}
server, err := grpc.New(serviceService)
if err != nil {
cleanup5()
cleanup4()
cleanup3()
cleanup2()
cleanup()
return nil, nil, err
}
app, cleanup6, err := NewApp(serviceService, engine, server)
if err != nil {
cleanup5()
cleanup4()
cleanup3()
cleanup2()
cleanup()
return nil, nil, err
}
return app, func() {
cleanup6()
cleanup5()
cleanup4()
cleanup3()
cleanup2()
cleanup()
}, nil
}
provider用法
var Provider = wire.NewSet(New, NewDB, NewRedis, NewMC)// 定义dao层的注入 在New 之后按照顺序添加,更具有易读性。
// New new a dao and return.
func New(r *redis.Redis, mc *memcache.Memcache, db *sql.DB) (d Dao, cf func(), err error) {
return newDao(r, mc, db)
}
wire.Bind 用法
wire.Bind(new(HelloInf), new(*HelloClass) // 定义一个结构体和接口的对应关系
// 类似java HelloInfService HelloServiceImpl