Golang依赖注入实战:从容器管理到应用实践
#作者:曹付江
文章目录
- 1、示例: 管理依赖关系的容器
- 1.1. 日志记录器设置
- 1.2. 数据库连接设置
- 1.3. 管理依赖关系的容器
- 2、如何使用容器
- 3、结论
依赖注入(DI)是一种在软件应用程序中促进松散耦合和可测试性的设计模式。它允许将依赖关系(如服务、配置或数据库)注入到组件中,而不是让组件直接创建或管理依赖关系。这将使代码更模块化、更易维护、更易测试。
在本篇文章中,我们将使用一个实用的 Golang 示例来探讨依赖注入模式。我们将分解代码,并解释如何在实际场景中实现依赖注入。
1、示例: 管理依赖关系的容器
该示例由三个 Go 文件组成,它们共同创建了一个 “容器”,用于管理日志记录器、数据库连接和配置等依赖项。让我们深入代码,看看 DI 是如何应用的。
1.1. 日志记录器设置
第一个文件使用 zap 日志库设置了一个日志记录器。日志记录器使用配置文件初始化,NewLogger 函数负责创建日志记录器实例。
func NewLogger(zapConfig string) (*zap.Logger, error) {file, err := os.Open(zapConfig)if err != nil {return nil, fmt.Errorf("failed to open logger config file")}defer file.Close()var cfg zap.Configif err := json.NewDecoder(file).Decode(&cfg); err != nil {return nil, fmt.Errorf("failed to parse logger config json")}logger, err := cfg.Build()if err != nil {return nil, err}defer logger.Sync()logger.Debug("logger construction succeeded")return logger, nil
}
这里,NewLogger 函数将配置文件路径(zapConfig)作为输入,并返回一个 zap.Logger 实例。这是构造函数注入的一个示例,依赖关系(日志记录器配置)被注入到函数中。
1.2. 数据库连接设置
第二个文件使用 gorm 库处理数据库连接。它定义了一个接口 Db 和两个实现(PostgresAdapter 和 MySQLAdapter),用于连接 PostgreSQL 和 MySQL 数据库。
type Db interface {MakeConnection() (*gorm.DB, error)
}
func NewDBConnectionAdapter(dbName, url string, dbMaxIdle, dbMaxOpen, dbMaxLifeTime, dbMaxIdleTime int, gormConf string) Db {switch dbName {case Postgres:return &PostgresAdapter{dbUrl: url, dbMaxIdle: dbMaxIdle, dbMaxOpen: dbMaxOpen, dbMaxLifeTime: dbMaxLifeTime, dbMaxIdleTime: dbMaxIdleTime, gormConf: gormConf}case Mysql:return &MySQLAdapter{dbUrl: url, dbMaxIdle: dbMaxIdle, dbMaxOpen: dbMaxOpen, dbMaxLifeTime: dbMaxLifeTime, dbMaxIdleTime: dbMaxIdleTime, gormConf: gormConf}}return &PostgresAdapter{dbUrl: url, dbMaxIdle: dbMaxIdle, dbMaxOpen: dbMaxOpen, dbMaxLifeTime: dbMaxLifeTime, dbMaxIdleTime: dbMaxIdleTime, gormConf: gormConf}
}
NewDBConnectionAdapter 函数作为一个工厂,根据 dbName 参数创建适当的数据库适配器。这是工厂注入的一个示例,由工厂决定注入哪个实现。
1.3. 管理依赖关系的容器
第三个文件定义了容器接口及其实现。容器负责管理所有依赖项(日志记录器、数据库等),并在需要时注入它们。
type Container interface {Logger() *zap.LoggerDb() *gorm.DBPort() stringPprofEnable() string
}
type container struct {logger *zap.Loggerdb *gorm.DBport stringpprofEnable stringenvironmentVariables map[string]string
}func New(envVars map[string]string) (Container, error) {c := &container{environmentVariables: envVars}var err errorc.db, err = c.dbSetup()if err != nil {return c, err}c.logger, err = c.loggerSetup()if err != nil {return c, err}c.port, err = c.portSetup()if err != nil {return c, err}c.pprofEnable, err = c.pprofEnableSetup()if err != nil {return c, err}return c, nil
}
New 函数通过设置所有依赖关系来初始化容器。它使用构造函数注入将环境变量和配置传递给容器。每个依赖项(日志记录器、数据库等)都是单独初始化的,从而使代码模块化并易于测试。
本示例中依赖注入的主要优点:
-
松耦合:容器不会直接创建其依赖关系。相反,它依赖外部配置和工厂来提供这些依赖。这使得代码更灵活、更易于修改。
-
可测试性:由于依赖关系是注入的,因此在测试过程中可以轻松地模拟它们。例如,您可以在单元测试中用模拟数据库替换真实数据库连接。
-
单一责任原则:每个组件(日志记录器、数据库适配器等)都有单一责任。容器只负责管理依赖关系,而不是创建依赖关系。
-
可重用性:数据库接口及其实现可在应用程序的不同部分重复使用。你可以在 PostgreSQL 和 MySQL 之间切换,而无需改变核心逻辑。
2、如何使用容器
下面介绍如何在应用程序中使用容器:
func main() {c, err := container.New(map[string]string{container.LogLevelEnvVar: os.Getenv(container.LogLevelEnvVar),container.DatabaseURLEnvVar: os.Getenv(container.DatabaseURLEnvVar),container.PortEnvVar: os.Getenv(container.PortEnvVar),container.DBMaxIdleEnvVar: os.Getenv(container.DBMaxIdleEnvVar),container.DBMaxOpenEnvVar: os.Getenv(container.DBMaxOpenEnvVar),container.DBMaxLifeTimeEnvVar: os.Getenv(container.DBMaxLifeTimeEnvVar),container.DBMaxIdleTimeEnvVar: os.Getenv(container.DBMaxIdleTimeEnvVar),container.ZapConf: os.Getenv(container.ZapConf),container.GormConf: os.Getenv(container.GormConf),container.PprofEnable: os.Getenv(container.PprofEnable),})if err != nil {defer func() {fmt.Println("server initialization failed error: %w", err)}()panic("server initialization failed")}logger := c.Logger()db := c.Db()logger.Info("Application started", zap.String("port", c.Port()))// Use db and logger in your application...
}
3、结论
依赖注入模式是构建模块化、可测试和可维护应用程序的强大工具。在这个示例中,我们看到了如何在 Go 中使用接口、工厂和容器来管理依赖关系,从而实现依赖注入。
通过采用 DI,您可以:
- 解耦应用程序的组件。
- 提高可测试性。
- 使你的代码更具可重用性和可维护性。
如果你是依赖注入的新手,鼓励你在自己的项目中尝试实施依赖注入。从小处着手,逐步重构代码,在合理的地方使用依赖注入。
相关文章:
Golang依赖注入实战:从容器管理到应用实践
#作者:曹付江 文章目录 1、示例: 管理依赖关系的容器1.1. 日志记录器设置1.2. 数据库连接设置1.3. 管理依赖关系的容器 2、如何使用容器3、结论 依赖注入(DI)是一种在软件应用程序中促进松散耦合和可测试性的设计模式。它允许将依…...

Node.js二:第一个Node.js应用
精心整理了最新的面试资料和简历模板,有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 创建的时候我们需要用到VS code编写代码 我们先了解下 Node.js 应用是由哪几部分组成的: 1.引入 required 模块:我们可以使用 requi…...

【Python爬虫】利用代理IP爬取跨境电商AI选品分析
引言 随着DeepSeek的流行,越来越多的用户开始尝试将AI工具融入到日常工作当中,借助AI的强大功能提高工作效率。最近又掀起了一波企业出海的小高潮,那么如果是做跨境电商业务,怎么将AI融入工作流中呢?在做跨境电商的时候…...
生命周期总结(uni-app、vue2、vue3生命周期讲解)
一、vue2生命周期 Vue2 的生命周期钩子函数分为 4 个阶段:创建、挂载、更新、销毁。 1. 创建阶段 beforeCreate:实例初始化之后,数据观测和事件配置之前。 created:实例创建完成,数据观测和事件配置已完成,…...
计算机数据库三级刷题总结(博主89分已过,总结的内容分享)
计算机数据库三级刷题总结(博主89分已过,总结的内容分享) 文章目录 计算机数据库三级刷题总结(博主89分已过,总结的内容分享)一、 数据库设计阶段二、事务相关三、数据库设计顺序四、数据库三级模式与二层映…...

mfc140u.dll是什么?当程序遭遇mfc140u.dll问题:快速恢复正常的秘诀
在使用Windows操作系统运行某些软件时,不少用户会遇到令人头疼的mfc140u.dll文件丢失错误。mfc140u.dll这个错误一旦出现,往往导致相关程序无法正常启动或运行,给用户带来诸多不便。这天的这篇文章将给大家分析mfc140u.dll是什么?…...

AI是否能真正理解人类情感?从语音助手到情感机器人
引言:AI与情感的交集 在过去的几十年里,人工智能(AI)的发展速度令人惊叹,从简单的语音识别到如今的深度学习和情感计算,AI已经深入到我们生活的方方面面。尤其是在语音助手和情感机器人领域,AI不…...

3.3.2 Proteus第一个仿真图
文章目录 文章介绍0 效果图1 新建“点灯”项目2 添加元器件3 元器件布局接线4 补充 文章介绍 本文介绍:使用Proteus仿真软件画第一个仿真图 0 效果图 1 新建“点灯”项目 修改项目名称和路径,之后一直点“下一步”直到完成 2 添加元器件 点击元…...

JetBrains学生申请
目录 JetBrains学生免费授权申请 IDEA安装与使用 第一个JAVA代码 1.利用txt文件和cmd命令运行 2.使用IDEA新建项目 JetBrains学生免费授权申请 本教程采用学生校园邮箱申请,所以要先去自己的学校申请校园邮箱。 进入JetBrains官网 点击立即申请,然…...

深入探索WebGL:解锁网页3D图形的无限可能
深入探索WebGL:解锁网页3D图形的无限可能 引言 。WebGL,作为这一变革中的重要技术,正以其强大的功能和广泛的应用前景,吸引着越来越多的开发者和设计师的关注。本文将深入剖析WebGL的核心原理、关键技术、实践应用,并…...
SQL进阶技巧:上课时长计算
目录 0 问题描述 1 数据准备 2 问题解决 核心难点 时间区间标记与分组 区间合并与时长计算...

“沂路畅通”便利服务平台:赋能同城物流,构建高效畅通的货运生态
“沂路畅通”便利服务平台:赋能同城物流,构建高效畅通的货运生态 随着城市化进程的加速,同城物流需求迅速增长,然而货运过程中仍然存在信息不对称、资源浪费、司机服务体验差等痛点。临沂呆马区块链网络科技有限公司(…...

文件上传靶场(1--9关)
实验环境: 1,upload的靶场环境可以去GitHub上自行查找 2,打开小皮面板的nginx和数据库 3,将文件上传的靶场部署到本地: 放到小皮的phpstduy_pro的www下面 小提示: 另外如果你用的是php7的版本建议将版…...

嵌入式 ARM Linux 系统构成(1):Bootloader层
目录 一、Bootloader 概述 1.1 核心作用 1.2 典型启动流程 二、ARM Bootloader 架构详解 2.1 多阶段启动设计 2.2 关键代码流程 2.3. Bootloader的加载过程 2.4. Bootloader的加载方式 2.5. Bootloader 的移植 三、常见的Bootloader介绍 3.1. U-Boot 3.2. vivi …...

ArcGIS Pro 基于基站数据生成基站扇区地图
在当今数字化的时代,地理信息系统(GIS)在各个领域都发挥着至关重要的作用。 ArcGIS Pro作为一款功能强大的GIS软件,为用户提供了丰富的工具和功能,使得数据处理、地图制作和空间分析变得更加高效和便捷。 本文将为您…...

GaussianCity:实时生成城市级数字孪生基底的技术突破
在空间智能领域,如何高效、大规模地生成高质量的3D城市模型一直是一个重大挑战。传统方法如NeRF和3D高斯溅射技术(3D-GS)在效率和规模上存在显著瓶颈。GaussianCity通过创新性的技术方案,成功突破了这些限制,为城市级数字孪生的构建提供了全新路径。 一、核心创新:突破传…...
【个人学习总结】反悔贪心:反悔堆+反悔自动机
参考:【学习笔记】反悔贪心 - RioTian 什么是反悔贪心? 反悔贪心,就是可以回溯的贪心,一般题目我们能使用正常贪心的情况是很少的,因为我们只考虑了局部最优解,我们不能保证局部最优解是最后的最优解&…...
通往 AI 之路:Python 机器学习入门-线性代数
2.1 线性代数(机器学习的核心) 线性代数是机器学习的基础之一,许多核心算法都依赖矩阵运算。本章将介绍线性代数中的基本概念,包括标量、向量、矩阵、矩阵运算、特征值与特征向量,以及奇异值分解(SVD&…...

迷你世界脚本UI五子棋小游戏
wzq_jm "7477124677881080183-22855"--界面id wzq_jmjxh "7477124677881080183-22855_"--界面加下划线 wzq_tc "7477124677881080183-22855_262"--退出按钮id wzq_hdlt1 "7477124677881080183-22855_267"--互动聊天按钮 快点吧&a…...

阿里万相,正式开源
大家好,我是小悟。 阿里万相正式开源啦。这就像是AI界突然开启了一扇通往宝藏的大门,而且还是免费向所有人敞开的那种。 你想想看,在这个科技飞速发展的时代,AI就像是拥有神奇魔法的魔法师,不断地给我们带来各种意想…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...
用 FFmpeg 实现 RTMP 推流直播
RTMP(Real-Time Messaging Protocol) 是直播行业中常用的传输协议。 一般来说,直播服务商会给你: ✅ 一个 RTMP 推流地址(你推视频上去) ✅ 一个 HLS 或 FLV 拉流地址(观众观看用)…...