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就像是拥有神奇魔法的魔法师,不断地给我们带来各种意想…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
