GoLang之使用uber-go/dig进行依赖注入

2023-10-27

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数据,参数是db
 personRepository := 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.Config
 personService *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)
  // 注入server
  container.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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GoLang之使用uber-go/dig进行依赖注入 的相关文章

  • Go语言之Gin框架引用静态资源CSS的方法

    参考资料 Go语言之Gin框架 xff0c 引用静态js css文件 xff0c 达到页面美化 打开网页提醒功能 原创 实践 目录结构 加载 span class token comment LoadStatic 加载静态资源 span s
  • 9-gin使用websocket

    toc gin使用websocket Gin 框架默认不支持 websocket xff0c 可以使用 github com gorilla websocket 实现 Talk is cheap Show me the code xff0c
  • go语言gin、net/http的优雅关机

    gin net http的优雅关机 什么是优雅关机 xff1f 优雅关机的实现参考链接 什么是优雅关机 xff1f http server运行过程中 xff0c 若进程被关闭 xff0c 那么正在处理的请求可能只被处理了一半就停止了 xff
  • go web gin框架实战1

    文章目录 go web gin框架实战1 参考资料2 demo3 demo运行4 demo解析 go web gin框架实战 1 参考资料 gin框架官方文档 链接 2 demo span class token keyword packa
  • Gin 框架的路由结构浅析

    Gin 是 go 语言的一款轻量级框架 xff0c 风格简单朴素 xff0c 支持中间件 xff0c 动态路由等功能 gin项目github地址 路由是web框架的核心功能 在没有读过 gin 的代码之前 xff0c 在我眼里的路由实现是这
  • gin 十. gin-contrib之secure 支持https与安全设置

    目录 一 实现https 二 防止XSS CSRF 一 实现https gin默认是http接口 前面也了解到gin中存在一个子包 gin contrib secure 内部提供了一些安全相关的中间件 例如HTTPS重定向 内容安全策略 C
  • go-gin 自定义应用metrics

    文章目录 前言 一 gin添加go运行时metrics 1 创建一个gin server 2 创建一个metrics的路由 3 启动服务 4 查看结果 metrics页面 pprof页面 二 gin自定义应用程序metrics 官方库示例
  • Go【gin和gorm框架】实现紧急事件登记的接口

    简单来说 就是接受前端微信小程序发来的数据保存到数据库 这是我写的第二个接口 相比前一个要稍微简单一些 而且因为前端页面也是我写的 参数类型自然是无缝对接 前端页面大概长这个样子 先用apifox模拟发送请求测试 apifox可以直接复制J
  • Gin微服务框架_golang web框架_完整示例Demo

    Gin简介 前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住分享一下给大家 点击跳转到网站 Gin是一个golang的微框架 封装比较优雅 API友好 源码注释比较明确 具有快速灵活 容错方便等特点 其实对于golang而
  • golang的web框架Gin(一)---Gin的安装与初体验

    简介 1 1 介绍 Go世界里最流行的Web框架 Github上有32K star 基于httprouter开发的Web框架 中文文档齐全 简单易用的轻量级框架 Gin是一个golang的微框架 封装比较优雅 API友好 源码注释比较明确
  • go 进阶 gin底层原理相关: 四. gin中间件底层原理

    目录 一 gin 中间件基础 二 中间件初始化流程 1 初始化中间件保存到RouterGroup的HandlersChain数组中 HandlersChain是什么 2 整合中间件函数与业务相关的mainHandler构建前缀树 三 中间件
  • 【golang】12、gin 源码解析

    文章目录 快速使用 返回响应 路由匹配 path query Multipart Urlencoded Form 解析请求 MultipartFrom MiddleWare github com gin gonic gin 是 golang
  • GinCMS 使用golang Gin框架xorm开发的小型内容管理系统

    系统介绍 服务器端 使用GoLang 基于Gin框架 MySQL数据库 用到的组件xorm 前端展示 使用基于LayUI的layuicms 用到的第三方组件authtree treeTable GinCMS是我学习golang 使用Gin开
  • gin 框架中的 gin.Context

    前言 Context 是 gin 中最重要的部分 例如 它允许我们在中间件之间传递变量 管理流程 验证请求的 JSON 并呈现 JSON 响应 Context 中封装了原生的 Go HTTP 请求和响应对象 同时还提供了一些方法 用于获取请
  • gin 六.重定向路由重定向与请求转发

    目录 一 重定向与请求转发基础解释 二 重定向 gin Context Redirect 内部 外部重定向 路由重定向 三 请求转发 一 重定向与请求转发基础解释 重定向和请求转发是两种常见的HTTP请求处理方式 它们都可以实现将请求从一个
  • gin 四.响应数据

    响应数据 一 响应数据 二 c Writer Header Set处理响应头 一 响应数据 在gin中请求接口响应时 实际可以响应会html text plain json和xml等 比如前面gin基础示例中 接口响应时可以使用 gin C
  • gin 三.请求数据的映射

    数据解析绑定 基础解释 ShouldBindWith 请求数据映射示例 ShouldBindHeader 将请求头绑定到一个结构体或接口示例 MustBindWith 方式 基础解释 解释 例如后端获取调用方参数 通常会使用一个结构体 或一
  • 使用go语言整合gin,驱动bartender打印标签程序

    可以用来当中间件 项目地址 github GitHub wjdsg0327 printer barTender 使用go语言整合gin驱动bartender打印标签 gitee printer barTender 使用go整合gin驱动ba
  • Gin之获取path参数

    文章目录 Gin之获取path参数 1 path参数介绍 2 获取一个 path参数 Param方法 3 获取二个 path参数 Param方法 4 获取 path参数 Param方法 5 获取一个 path参数 ShouldBindUri
  • GoLong的学习之路,进阶,Viper(yaml等配置文件的管理)

    本来有今天是继续接着上一章写微服务的 但是这几天有朋友说 再写Web框架的时候 遇到一个问题 就是很多的中间件 redis 微信 mysql mq 的配置信息写的太杂了 很不好管理 希望我能写一篇有管理配置文件的 所以这篇就放到今天写吧 微

随机推荐

  • 2022百度之星初赛总结(非题解)

    完了玩废了 0题罚坐 下来看题解 是有简单题 完全完全能做的 大一这都没罚坐 悲 ccpc预选赛开始了 希望队友健在 T1 从dij到bf到fl 判定条件是等于 与公开ac是惊人的像 但样例都没调出来 T2 题目k 1 k n理解为n 1到
  • 晶体管 放大电路的 分析

    三极管共集电极放大电路和共基极放大电路详解 https wenku baidu com view 036f033a31b765ce050814c4 html 共集电极放大电路 https wenku baidu com view 204a7
  • RDS MySQL空间优化最佳实践

    简介 在前三期介绍了RDS for MySQL参数优化 锁问题以及延迟优化最佳实践之后 本期将介绍存储空间相关的最佳实践 存储空间是RDS很重要的一个指标 在RDS的工单问题中 空间问题的咨询可以排在top 5 当RDS的实际使用空间超过了
  • android手机销售app(IDEA,SpringBoot,SSM,MySQL)+支付宝支付+全套视频教程

    本项目亮点 支付宝支付 eCharts柱状图图表数据统计 项目功能介绍 本系统包含后台管理和前端app双端系统 后台管理的功能包含 登录 退出 修改管理员信息 基本信息与头像 资源管理 角色管理 资源权限分配 字典管理 用户管理 图书管理
  • Matlab学习4-图像处理之图像加法、图像减法、加噪

    图像处理 图像加法 例图像的叠加 调亮色等 图像减法 例捕捉运动图像的轨迹 环境matlab2020 使用imadd 加 imsubtract 减 imresize 改 imnoise 图像加噪 matlab函数 imadd X Y 将两个
  • 农业温室大棚养殖系统智能监控方案

    温室大棚农作物的种植给人们的生活带来极大的便利 并得到了迅速的推广和应用 在不适宜植物生长的季节 为保证作物温室生育期和作物产量 实时地收集温度 湿度 光照 气体浓度以及土壤水分等信息并汇总物通博联智能网关上传到物通博联云 为了给农作物创造
  • WebSocket 协议使用

    WebSocket 协议实现在受控环境中运行不受信任代码的一个客户端到一个从该代码已经选择加入通信的远程主机之间的全双工通信 用于这个的安全模型是通 常由 web 浏览器使用的基于来源的安全模型 该协议包括一个打开阶段握手 接着是基本消息帧
  • 数据分析之数据预处理、分析建模、可视化

    大纲 思维导图 1 数据分析概述 1 1 简介 1 2 发展历程 1 3 应用领域 1 4 开发流程 2 数据类型 2 1 结构化与非结构化数据 2 2 定性与定量数据 2 3 截面数据与时间序列数据 3 数据来源 4 数据预处理方法 4
  • 初始vue(二)

    vue详细学习 二 class的操作 div class play judge data judge true div data msg div 1212323 div data msg div 1212323 div 不能解析 的内容 d
  • 【深度学习】Pytorch 系列教程(一):PyTorch数据结构:1、Tensor(张量):维度(Dimensions)、数据类型(Data Types)

    目录 一 前言 二 实验环境 三 PyTorch数据结构 0 分类 1 Tensor 张量 1 维度 Dimensions 0维 标量 1维 向量 2维 矩阵 3维张量 2 数据类型 Data Types 一 前言 ChatGPT PyTo
  • linux中gvim配置

    文章目录 前言 一 在哪配置 二 设置语句 三 运行结果 前言 对于在linux上工作的硬件工程师来说 换到一个新的服务器或者工作环境 首先要做的几件事中肯定有一项是设置gvim配置 这里纪录下我的常用gvim配置和注释 仅供参考 如有错误
  • mysql TRUNCATE delete

    mysql truncate 和delete 都用与删除数据表里的数据 truncate命令则是直接将全表的数据清空掉 delete命令可以不带where 可以达到同样的目的 delete通过where带上条件删除部分数据 从这可以看出de
  • Nginx_http_upstream_check_module应用

    ngx http upstream check module 该模块可以为Nginx提供主动式后端服务器健康检查的功能 该模块在Nginx 1 4 0版本以前没有默认开启 它可以在配置编译选项的时候开启 configure with htt
  • C++的特性(封装、继承、多态、抽象)的详解

    封装 封装目的 模块化 信息隐藏 封装 隐藏对象的属性和实现细节 仅对外公开接口和对象进行交互 将数据和操作数据的方法进行有机结合 是通过特性和行为的组合来创建新数据类型让接口与具体实现相隔离 C 中是通过类来实现的 为了尽量避免某个模块的
  • MIPI I3C简介

    前面的文章介绍过MIPI联盟发布的MIPI CSI DSI D PHY等接口 这一篇文章来简单聊一聊I3C 同样由MIPI联盟制定 主要用于替代传统的USRT I2C和SPI 并向下兼容I2C 由于已经有网友写过相关的文章 并且写的很不错
  • signature=462fd3702561f02c1dc8858a887d01f8,baly-20201118

    0001747079 20 000139 txt 20201119 0001747079 20 000139 hdr sgml 20201119 20201119073031 ACCESSION NUMBER 0001747079 20 0
  • EF(Entity Framework)通用DBHelper通用类,增删改查以及列表

    其中 通用类名 DBhelper 实体类 UserInfo 1 新增 2 DBHelper
  • wedo巡线机器人编程教程_这是一个机器人和编程的时代

    图中在草地上自在奔跑的机器人是波士顿动力公司 BostonDynamics 开发的类人双足机器人Atlas 由麻省理工 MIT 电子工程与计算机科学系的教授马克 雷波特在1992年创立 一直致力于将机器人变成自然界的一个新物种 经过20多年
  • Springboot集成knife4j实现风格化API文档

    Springboot集成knife4j实现风格化API文档 POM引入插件
  • GoLang之使用uber-go/dig进行依赖注入

    文章目录 GoLang之使用uber go dig斤进行依赖注入 1 依赖输注入介绍 2 main函数反面例子 3 下载DI依赖 4 main函数使用DI优化 5 注意点 GoLang之使用uber go dig斤进行依赖注入 注 本文是基