文章目录

  • 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进行依赖注入相关推荐

  1. golang 依赖注入 dig详解

    golang的依赖注入dig 一篇文章带你了解golang依赖注入 dig介绍: dig 库是一个为 go 提供依赖注入 (dependency injection) 的工具包,基于 reflecti ...

  2. Golang 实现依赖注入

    Golang 实现依赖注入 什么是依赖注入 依赖注入就是将实例变量传入到一个对象中去 为何要做依赖注入 让开发者从对项目中大量依赖的创建和管理中解脱出来 控制反转(IoC)与依赖注入(DI) 控制反转 ...

  3. Golang 依赖注入

    1. 手动实现依赖注入 package mainimport "fmt"type A struct {B *B }type B struct {Inject string }fun ...

  4. 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 ...

  5. 【golang】实现依赖注入

    依赖注入 一.控制反转是什么? 1.如何理解 Ioc 呢? 2.控制反转和依赖注入 3.小总结 二.依赖注入代码实现    使用过 Java 的一定知道依赖注入这个概念,说到依赖注入就不得不提一下控制 ...

  6. 依赖注入框架 wire

    在上一篇文章当中我们讲到了项目的目录结构,大体上水平切分为了四层,然后再根据需要进行垂直切分,然后由于我们大量的使用到了接口和依赖注入的手段,所以在项目初始化的时候如果手动进行依赖关系的初始化会比较麻 ...

  7. go依赖注入--google开源库wire

    目录 1. wire的使用好处 2. 安装wire工具 3. wire是怎么工作的 3. 我们怎么来使用wire 4. wire的高级特性 5.参考资料 如果使用过java的小伙伴一定对依赖注入( d ...

  8. 浅谈“面向接口编程” :依赖反转 IOC 与 DI (容器控制反转与依赖注入)

    IOC:Inversion of Control Containers and the Dependency Injection "Water" by Andy Huan, Mal ...

  9. 依赖注入和反转控制的区别

    依赖注入和反转控制的区别 写在前面,这篇文章是一个外国人写的,我还没有翻译过来,怕自己忘了,先粘到csdn上面. 原来文章的地址 One of the entertaining things abou ...

  10. Java 控制反转和依赖注入模式【翻译】【整理】

    Inversion of Control Containers and the Dependency Injection pattern --Martin Fowler 本文内容 Component ...

最新文章

  1. install python+twisted+mysqldb+django on mac
  2. 人工智能乌托邦 迪拜认为2071年人类应该这样生活!
  3. “赶上热词热概念,是我们不幸的一面” | 对话小冰公司CEO李笛
  4. 目标跟踪学习算法DSST
  5. vivado2017.4安装教程
  6. QT的QQmlExpression类的使用
  7. AD9516/AD9517时钟芯片寄存器参数配置说明
  8. linux内核热修复,揭露内核黑科技 - 热补丁技术真容
  9. 微服务配置中心实战:Spring + MyBatis + Druid + Nacos 1
  10. 尚硅谷kubernates学习笔记 1
  11. The Things Network LoRaWAN Stack V3 学习笔记 2.6 新增一个 CN470 子频段
  12. mac打开nh文件-cajviewer.dmg
  13. pytorch教程 聊天机器人(详细注释attentionrnn输入输出shape等知识点...
  14. java递归把list菜单列表转为菜单树
  15. 第一次作业:我和计算机
  16. ​格林纳达新任常驻WTO代表孙宇晨:用数字技术助推加勒比地区经济
  17. 谷歌浏览器禁止打开某些网站
  18. 怎么将iMindMap制作的思维导图转换为甘特图?
  19. Python爬虫入门 | 4 爬取豆瓣TOP250图书信息
  20. Vue3 移动端浏览器底部工具栏挡住部分网页,以及ios网页放大滑动问题。

热门文章

  1. 新一线城市竞争力盘点,用Python绘制动态图带你看懂!
  2. .NET6东西--可写的JSON DOM API
  3. 510房产网是江阴知名的房地产服务平台
  4. Java并发 ReentrantLock(重入锁)之非公平锁源码解析 超详细!!
  5. 翁恺慕课C语言作业 第三章时区换算
  6. 北京大学陈斌教授 python_好老师陈斌,这样在北大走红
  7. java 多个文件合并,多个 MP3 合并,InputStream 合并
  8. 半闲居士视觉SLAM十四讲笔记(3)三维空间刚体运动 - part 3 旋转向量、欧拉角、四元数
  9. 计算机编程实训视频教程,C++网络编程实践视频教程 共84节课 陈硕主讲
  10. CSS:absolute绝对定位