go 的 wire 依赖注入
什么是依赖注入
依赖注入是实现 控制反转 的一种方式,即把功能函数所依赖的其他服务作为入参
注入,而非在函数内部声明。
以学生对象为例,该对象具备 db 和 log 两个属性,声明此对象有以下两种方式:
- 不使用依赖注入,所需的依赖在函数体内实现:
复制type StudentRepo struct {
db *gorm.DB
log *logrus.Logger
}
func NewStudentRepo() (*StudentRepo, error) {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
return nil, err
}
log := logrus.New()
return &StudentRepo{db: db, log: log}, nil
}
2.使用依赖注入,所需对象由外部传入:
func NewStudentRepo(db *gorm.DB, log *logrus.Logger) *StudentRepo {
return &StudentRepo{
db: db,
log: log,
}
}
通过上述示例了解依赖注入后,理解较为抽象的控制反转
就更容易了。若要将学生对象
中 db 使用的 sqlite 替换为 mysql,无需修改 repo 层代码,只需在声明对象处进行更改。
控制反转(Inversion of Control,IOC)是一种设计原则,它让我们能够将程序的控制权从程序本身转移到外部容器或框架上。
使用 wire 工具,帮助我们实现依赖注入的代码
首先安装 wire
工具
go install github.com/google/wire/cmd/wire@latest
基本概念
- Wire 是一个的 Google 开源的依赖注入工具,通过自动生成代码的方式在编译期完成依赖注入。
wire
工具,需要两个核心组件:提供者(provider)
和注入器(injector)
,结合下面简单的例子来看
a. 提供者就是能 new对象 的函数
b. 注入者就是最后想要的引用函数的模板- wire 命令,必须在
wire.go
所在的同级目录下执行
示例项目
构建一个示例项目,目录结构大致如下:
.
├── go.mod
├── go.sum
├── main.go
├── wire.go
└── wire_gen.go
go 文件
main.go 文件如下
type StudentRepo struct {
db *gorm.DB
log *logrus.Logger
}
type Student struct {
repo *StudentRepo
}
func NewDb(filePath string) (*gorm.DB, error) {
return gorm.Open(sqlite.Open(filePath), &gorm.Config{})
}
func NewLog() *logrus.Logger {
return logrus.New()
}
func NewStudentRepo(db *gorm.DB, log *logrus.Logger) *StudentRepo {
return &StudentRepo{db: db, log: log}
}
func NewStudent(repo *StudentRepo) *Student {
return &Student{
repo: repo,
}
}
// 使用 wire.NewSet 可以把所有的构建者,放到一个集合中
var ProviderSet = wire.NewSet(NewDb, NewLog, NewStudentRepo, NewStudent)
wire.go 文件如下
//go:build wireinject
package main
import "github.com/google/wire"
// 声明提供者
func InitStudent(sqlitePath string) (*Student, error) {
wire.Build(ProviderSet)
return &Student{}, nil
}
- 在
wire.go
文件所在的目录,执行wire
命令,生成 wire_gen.go 文件。 - 文件名
wire.go
可以随便定义,wire 命令是根据开头的注释找的,寻找注入器所在的文件,而不是文件名,具体文件标识符的用法,可以参考 https://juejin.cn/post/7126461083837005838
//go:build wireinject
- 注入器函数
wire.go
,本质就是一个模板,其实不需要完全符合go
语言语法,简单处理如下
最终生成的 wire_gen.go
文件如下
// Code generated by Wire. DO NOT EDIT.
//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
// Injectors from wire_ss.go:
// 声明提供者
func InitStudent(sqlitePath string) (*Student, error) {
db, err := NewDb(sqlitePath)
if err != nil {
return nil, err
}
logger := NewLog()
studentRepo := NewStudentRepo(db, logger)
student := NewStudent(studentRepo)
return student, nil
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?