选型Go项目过程中,针对依赖注入方式的分析和使用
Wire 是一个轻巧的Golang依赖注入工具。它由Go Cloud团队开发,通过自动生成代码的方式在编译期完成依赖注入。
依赖注入是保持软件 “低耦合、易维护” 的重要设计准则之一
同类型哦工具有:来自Uber 的 dig 、来自Facebook 的 inject,下边我们只对比下wire和dig
uber 推出的依赖注入库,采用反射,在运行时计算依赖关系,构造依赖对象。
上面简单介绍了wire 和 dig 两者之间的特点:
1、dig 通过反射识别依赖关系,wire 是编译前计算依赖关系
2、dig 只能在代码运行时,才能知道哪个依赖不对,比如构造函数返回类型的是结构体指针,但是其他依赖的是interface,这样的错误只能在运行时发现,而wire可以在编译的时候就发现。
3、由于采用了依赖注入,所以在代码调试时可以注入一些mock 服务或者函数,wire在mock上支持更友好些,dig的话可以通过build tag 来使用mock。 个人比较推荐使用wire,可以在编译时就发现问题,避免了 多次的build和尝试后才解决编译问题。更多的使用方式和最佳实践,可以参考官方文档。
根据依赖倒置原则(Dependence Inversion Principle),对象应当依赖于接口,而不是直接依赖于具体实现。
provider: a function that can produce a value. These functions are ordinary Go code.
injector: a function that calls providers in dependency order. With Wire, you write the injector’s signature, then Wire generates the function’s body.
wire 依赖注入方式想要达到的效果:
我们有一个主函数:
func main() {
message := NewMessage()
greeter := NewGreeter(message)
event := NewEvent(greeter)
event.Start()
}
我们改成这样:
func main() {
event := InitializeEvent()
event.Start()
}
├── routes
│ ├── init_server.go
│ ├── routes.go
│ ├── wire.go
│ └── wire_gen.go
//go:build wireinject
// +build wireinject
package routes
import (
"gdonline_backend/databases/redis"
"github.com/google/wire"
"github.com/rs/zerolog"
"gorm.io/gorm"
"gdonline_backend/internal/controller"
"gdonline_backend/internal/dao"
"gdonline_backend/internal/service"
)
var chpoPhenotype = wire.NewSet(
dao.NewChpoPhenotypeDao,
wire.Bind(new(dao.IChpoPhenotypesDao), new(*dao.ChpoPhenotypesDao)),
service.NewChpoPhenotypeService,
controller.NewChpoPhenotypesController,
)
func InitChpoPhenotypes(db *gorm.DB, log *zerolog.Logger) *controller.ChpoPhenotypesController {
panic(wire.Build(chpoPhenotype))
}
// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package routes
import (
"gdonline_backend/databases/redis"
"gdonline_backend/internal/controller"
"gdonline_backend/internal/dao"
"gdonline_backend/internal/service"
"github.com/google/wire"
"github.com/rs/zerolog"
"gorm.io/gorm"
)
// Injectors from wire.go:
func InitChpoPhenotypes(db *gorm.DB, log *zerolog.Logger) *controller.ChpoPhenotypesController {
chpoPhenotypesDao := dao.NewChpoPhenotypeDao(db, log)
chpoPhenotypesService := service.NewChpoPhenotypeService(chpoPhenotypesDao)
chpoPhenotypesController := controller.NewChpoPhenotypesController(chpoPhenotypesService)
return chpoPhenotypesController
}
// wire.go:
var chpoPhenotype = wire.NewSet(dao.NewChpoPhenotypeDao, wire.Bind(new(dao.IChpoPhenotypesDao), new(*dao.ChpoPhenotypesDao)), service.NewChpoPhenotypeService, controller.NewChpoPhenotypesController)
# routes>init_server.go
func InitServer() {
// 初始化数据库连接
db := mysql.DB
redisDB := redis.DB
zeroLog := logging.NewZerolog("business")
// 注册服务-wire
cc = InitChpoPhenotypes(db, zeroLog)
}
# main.go
routes.InitServer()
func Routes(r *gin.Engine) {
// 设置路由组: v1
v1 := r.Group("v1")
chpoPhenotype := v1.Group("chpo_phenotypes")
// 知识库管理
chpoPhenotype.GET("lists", cc.Lists) // 列表接口
chpoPhenotype.GET("detail", cc.Detail) // 获取表型详情
chpoPhenotype.POST("add", cc.Add) // 新增
chpoPhenotype.POST("edit", cc.Edit) // 编辑
chpoPhenotype.POST("delete", cc.Delete) // 删除
}