GoLang之使用uber-go/dig进行依赖注入
文章目录
- GoLang之使用uber-go/dig斤进行依赖注入
- 1.依赖输注入介绍
- 2.main函数反面例子
- 3.下载DI依赖
- 4.main函数使用DI优化
- 5.注意点
GoLang之使用uber-go/dig斤进行依赖注入
注:本文是基于Windos系统上Go SDK v1.8、 github.com/uber-go/dig@v1.14.1进行讲解;
1.依赖输注入介绍
本文介绍在golang中如何通过依赖注入(Dependency Inject,简称DI)管理全局服务。
DI是把有依赖关系的类放到容器中,解析出这些类的实例,就是依赖注入。
2.main函数反面例子
直接看,你会发现main()包含清晰的初始化流程。
但是仔细想想,随着业务的扩展,我们如果把基础服务的所有实例都在main函数里生成,即 config、db、person、Repository、server等,main函数将变得越来越臃肿。
而且如果有其他方法使用上面的实例时,需要通过参数的方式传递给方法所在包,例如:service.NewPersonService(config, personRepository),需要将config、personRepository传递给service包
func main() {// 生成config实例config := NewConfig()// 连接数据库db, err := ConnectDatabase(config)// 判断是否有错误if err != nil {panic(err)}// 生成repository实例,用于获取person数据,参数是dbpersonRepository := repo.NewPersonRepository(db)// 生成service实例,用于调用repository的方法personService := service.NewPersonService(config, personRepository)// 生成http服务实例server := NewServer(config, personService)// 启动http服务server.Run()
}
// main包下的函数
func NewServer(config *config.Config, service *service.PersonService) *Server {return &Server{config: config,personService: service,}
}
// main包下的函数
func NewConfig() *Config {// ...
}
// main包下的函数
func ConnectDatabase(config *config.Config) (*sql.DB, error) {// ...
}
//repo包下的函数
func NewPersonRepository(database *sql.DB) *PersonRepository {// ...
}
//service包下的函数
func NewPersonService(config *config.Config, repository *repo.PersonRepository) *PersonService {// ...
}
// Server
type Server struct {config *config.ConfigpersonService *service.PersonService
}
// Server下的方法,ServerHandler
func (s *Server) Handler() http.Handler {mux := http.NewServeMux()mux.HandleFunc("/people", s.people)return mux
}
//Server下的方法, Run
func (s *Server) Run() {httpServer := &http.Server{Addr: ":" + s.config.Port,Handler: s.Handler(),}httpServer.ListenAndServe()
}
// Server下的方法,people
func (s *Server) people(w http.ResponseWriter, r *http.Request) {people := s.personService.FindAll()bytes, _ := json.Marshal(people)w.Header().Set("Content-Type", "application/json")w.WriteHeader(http.StatusOK)w.Write(bytes)
}
3.下载DI依赖
我使用的是uber的dig包
go get github.com/uber-go/dig
4.main函数使用DI优化
这样的main函数不需要包含任何基础实例的初始化和参数传递的过程,可以称之:Perfect!
下面是对main函数里基础服务注入的流程说明:
1)BuildContainer,只将各个基础服务的实例化方法注入到容器里,还没有调用这些方法来实例化基础服务
2)container.Invoke,这里将会从容器里寻找server实例,来运行server.Run()。如果实例不存在,则调用其实例化的方法,NewServer
3)因为
NewServer(config *config.Config, service *service.PersonService) *Server
依赖于config.Config和service.PersonService,
故触发NewConfig、NewPersonService
4)NewConfig不依赖于任何实例,故可以成功返回config.Config实例
5)NewPersonService(config *config.Config, repository *repo.PersonRepository) *PersonService
依赖
config.Config和repo.PersonRepository
,继而触发repo.NewPersonRepository去实例化repo.PersonRepository
6)repo.NewPersonRepository方法依赖于db,
故触发ConnectDatabase方法,用来连接数据库,实例化db实例
7)最后递归倒推回去,完成所有实例的初始化与注入,调用server.Run()方法启动http服务。
注意,有依赖的初始化方法,需要放在前置依赖注入之后,比如container.Provide(ConnectDatabase)就放在container.Provide(NewConfig)之后。如果找不到初始化需要的依赖对象,在Invoke时就会报错。
// 构建一个DI容器
func BuildContainer() *dig.Container {container := dig.New()// 注入config的实例化方法container.Provide(NewConfig)// 注入database的实例化方法container.Provide(ConnectDatabase)// 注入repository的实例化方法container.Provide(repo.NewPersonRepository)// 注入service的实例化方法container.Provide(service.NewPersonService)// 注入servercontainer.Provide(NewServer)return container
}func main() {container := BuildContainer()err := container.Invoke(func(server *Server) {server.Run()})if err != nil {panic(err)}
}
5.注意点
之前我通过下面的方式去获取容器里的基础实例:
package app
// Config 配置文件
func Config() (conf *config.Config) {_ = container.Invoke(func(c *config.Config) {conf = c})return
}// 其他package
fmt.Println(app.Config().GetString("someKey"))
这样去获取基础实例是不正确的用法,因为底层是通过一个map来管理这些实例的,我们都知道不是线程安全的,在频繁调用时会出现以下错误:
注:concurret是"同时发生的意思"
所以,我们在使用注入的时候,将如这样依赖和的实例函数,在main函数里通过注入进去,这样仅调用一次,保证线程安全。d
GoLang之使用uber-go/dig进行依赖注入相关推荐
- golang 依赖注入 dig详解
golang的依赖注入dig 一篇文章带你了解golang依赖注入 dig介绍: dig 库是一个为 go 提供依赖注入 (dependency injection) 的工具包,基于 reflecti ...
- Golang 实现依赖注入
Golang 实现依赖注入 什么是依赖注入 依赖注入就是将实例变量传入到一个对象中去 为何要做依赖注入 让开发者从对项目中大量依赖的创建和管理中解脱出来 控制反转(IoC)与依赖注入(DI) 控制反转 ...
- Golang 依赖注入
1. 手动实现依赖注入 package mainimport "fmt"type A struct {B *B }type B struct {Inject string }fun ...
- uber fx_使用uber fx简化依赖注入
uber fx TL; DR (TL;DR) Here you can find the full example on Github.Here you can find a link to Uber ...
- 【golang】实现依赖注入
依赖注入 一.控制反转是什么? 1.如何理解 Ioc 呢? 2.控制反转和依赖注入 3.小总结 二.依赖注入代码实现 使用过 Java 的一定知道依赖注入这个概念,说到依赖注入就不得不提一下控制 ...
- 依赖注入框架 wire
在上一篇文章当中我们讲到了项目的目录结构,大体上水平切分为了四层,然后再根据需要进行垂直切分,然后由于我们大量的使用到了接口和依赖注入的手段,所以在项目初始化的时候如果手动进行依赖关系的初始化会比较麻 ...
- go依赖注入--google开源库wire
目录 1. wire的使用好处 2. 安装wire工具 3. wire是怎么工作的 3. 我们怎么来使用wire 4. wire的高级特性 5.参考资料 如果使用过java的小伙伴一定对依赖注入( d ...
- 浅谈“面向接口编程” :依赖反转 IOC 与 DI (容器控制反转与依赖注入)
IOC:Inversion of Control Containers and the Dependency Injection "Water" by Andy Huan, Mal ...
- 依赖注入和反转控制的区别
依赖注入和反转控制的区别 写在前面,这篇文章是一个外国人写的,我还没有翻译过来,怕自己忘了,先粘到csdn上面. 原来文章的地址 One of the entertaining things abou ...
- Java 控制反转和依赖注入模式【翻译】【整理】
Inversion of Control Containers and the Dependency Injection pattern --Martin Fowler 本文内容 Component ...
最新文章
- install python+twisted+mysqldb+django on mac
- 人工智能乌托邦 迪拜认为2071年人类应该这样生活!
- “赶上热词热概念,是我们不幸的一面” | 对话小冰公司CEO李笛
- 目标跟踪学习算法DSST
- vivado2017.4安装教程
- QT的QQmlExpression类的使用
- AD9516/AD9517时钟芯片寄存器参数配置说明
- linux内核热修复,揭露内核黑科技 - 热补丁技术真容
- 微服务配置中心实战:Spring + MyBatis + Druid + Nacos 1
- 尚硅谷kubernates学习笔记 1
- The Things Network LoRaWAN Stack V3 学习笔记 2.6 新增一个 CN470 子频段
- mac打开nh文件-cajviewer.dmg
- pytorch教程 聊天机器人(详细注释attentionrnn输入输出shape等知识点...
- java递归把list菜单列表转为菜单树
- 第一次作业:我和计算机
- ​格林纳达新任常驻WTO代表孙宇晨:用数字技术助推加勒比地区经济
- 谷歌浏览器禁止打开某些网站
- 怎么将iMindMap制作的思维导图转换为甘特图?
- Python爬虫入门 | 4 爬取豆瓣TOP250图书信息
- Vue3 移动端浏览器底部工具栏挡住部分网页,以及ios网页放大滑动问题。
热门文章
- 新一线城市竞争力盘点,用Python绘制动态图带你看懂!
- .NET6东西--可写的JSON DOM API
- 510房产网是江阴知名的房地产服务平台
- Java并发 ReentrantLock(重入锁)之非公平锁源码解析 超详细!!
- 翁恺慕课C语言作业 第三章时区换算
- 北京大学陈斌教授 python_好老师陈斌,这样在北大走红
- java 多个文件合并,多个 MP3 合并,InputStream 合并
- 半闲居士视觉SLAM十四讲笔记(3)三维空间刚体运动 - part 3 旋转向量、欧拉角、四元数
- 计算机编程实训视频教程,C++网络编程实践视频教程 共84节课 陈硕主讲
- CSS:absolute绝对定位