go依赖注入库samber/do使用
英语版本
介绍
以简单和高效而闻名的Go语言在其1.18版本中引入了泛型,这可以显着减少大量代码生成的需要,使该语言更加强大和灵活。如果您有兴趣, Go 泛型教程 是很好的学习资源。
通过使用 Go 的泛型,samber/do库为依赖注入 (DI) 提供了一个很好的解决方案。依赖注入是一种重要的设计模式,它促进对象及其依赖关系之间的松散耦合,从而提高代码模块化性、可测试性和可维护性。泛型和依赖注入的结合进一步提升了 Go 在创建高效、可扩展软件方面的潜力。在本文中,您将学习如何使用 samber/do 提供依赖注入。
代码结构
.
├── cmd
│ └── web
│ └── main.go
├── domain
│ └── user.go
├── go.mod
├── go.sum
└── user├── handler.go├── repository.go└── service.go
我们使用与这篇博客相同的示例,但使用samber/do 库来实现 DI 而不是 Google Wire。正如我们所看到的,代码的结构变得更加简单。您可以在 https://github.com/Shujie-Tan/do-example 找到源代码。
服务关系
domain /user.go定义了业务逻辑结构和接口,如下所示。
type (User struct {ID string `json:"id"`Username string `json:"username"`}UserEntity struct {ID stringUsername stringPassword string}UserRepository interface {FetchByUsername(ctx context.Context, username string) (*UserEntity, error)}UserService interface {FetchByUsername(ctx context.Context, username string) (*User, error)}UserHandler interface {FetchByUsername() http.HandlerFunc}
)
在用户目录下可以看到这些接口的实现。其关系可以表示为
UserHandler -> UserService -> UserRepository -> sql.DB
这意味着UserHandler依赖于UserService,而 UserService 又依赖于UserRepository,最后UserRepository依赖于sql.DB进行数据库操作。这些依赖关系可通过使用接口来反转。
这是一个很简单的例子。现在我们构建对象及其依赖关系。
cmd/web/main.go
package mainimport ("database/sql""example/domain""example/user""fmt""net/http"_ "github.com/lib/pq""github.com/samber/do"
)func main() {injector := do.New() // 1connStr := "user=root dbname=mydb"db, err := sql.Open("postgres", connStr) // 2if err != nil {panic(err)}defer db.Close()do.ProvideNamed[*sql.DB](injector, "user", func(i *do.Injector) (*sql.DB, error) {return db, nil}) // 3do.Provide(injector, user.NewRepository)do.Provide(injector, user.NewService)do.Provide(injector, user.NewHandler) // 4userHandler := do.MustInvoke[domain.UserHandler](injector) // 5http.Handle("/user", userHandler.FetchByUsername())fmt.Printf("Try run server at :%d\n", 8080)if err := http.ListenAndServe(":8080", nil); err != nil {fmt.Printf("Error: %v", err)}
}
我们逐步分析一下代码:
- main 函数首先使用
injector := do.New()创建一个新的 DI 容器。该容器将用于管理应用程序对象的依赖关系。 - 使用
sql.Open函数建立与 PostgreSQL 数据库的连接。 - 使用
do.ProvideNamed函数将数据库连接添加到 DI 容器。该函数采用三个参数:DI 容器、依赖项的名称以及返回依赖项和错误的提供程序函数。在本例中,依赖项是数据库连接,该函数仅返回连接并返回 nil 来表示错误。 - 使用
do.Provide函数将repository、service和handler添加到 DI 容器。该函数有两个参数:DI 容器和返回依赖项和错误的函数。在本例中,函数是user.NewRepository、user.NewService和user.NewHandler,它们分别创建repository、service和handler的实例。请注意提供程序函数的返回类型应该是接口,而不是具体类型。因为我们不想依赖具体类型,而是依赖接口! - 使用
do.MustInvoke函数从 DI 容器检索userHandler并将其注册到 http 包。该函数采用两个参数:DI 容器和要检索的依赖项的类型。在本例中,它检索用户处理程序并将其FetchByUsername方法注册为 /user 路由的处理程序。
用户/repository.go
package userimport ("context""database/sql""example/domain""github.com/samber/do"
)type repository struct {db *sql.DB
}func (r *repository) FetchByUsername(ctx context.Context, username string) (*domain.UserEntity, error) {// use db here
}// the return type of NewRepository should be interface, rather than the concrete type!
func NewRepository(i *do.Injector) (domain.UserRepository, error) {db := do.MustInvokeNamed[*sql.DB](i, "user")return &repository{db: db}, nil
}
user/service.go
package userimport ("context""example/domain""github.com/samber/do"
)type service struct {repo domain.UserRepository
}func (s *service) FetchByUsername(ctx context.Context, username string) (*domain.User, error) {// use repository here
}func NewService(i *do.Injector) (domain.UserService, error) {repo := do.MustInvoke[domain.UserRepository](i)return &service{repo: repo}, nil
}
user/handler.go
package userimport ("example/domain""net/http""github.com/samber/do"
)type handler struct {svc domain.UserService
}func (h *handler) FetchByUsername() http.HandlerFunc {// use service here
}func NewHandler(i *do.Injector) (domain.UserHandler, error) {svc := do.MustInvoke[domain.UserService](i)return &handler{svc: svc}, nil
}
结论
在本文中,我们学习了如何使用samber/do在 Go 中提供依赖注入。我们已经了解了如何创建 DI 容器、向容器添加依赖项以及从容器中检索依赖项。我们还了解了如何使用容器来管理应用程序的依赖项。通过使用samber/do,我们可以创建更加模块化、可测试和可维护的代码,并充分利用 Go 的新泛型功能。
如果您有任何问题或反馈,请随时在下面发表评论。感谢您的阅读!
相关文章:
go依赖注入库samber/do使用
英语版本 介绍 以简单和高效而闻名的Go语言在其1.18版本中引入了泛型,这可以显着减少大量代码生成的需要,使该语言更加强大和灵活。如果您有兴趣, Go 泛型教程 是很好的学习资源。 通过使用 Go 的泛型,samber/do库为依赖注入 (…...
JMeter 配置元件之按条件读取CSV Data Set Config
实践环境 win10 JMeter 5.4.1 需求描述 需求是这样的,需要压测某个接口(取消分配接口),请求这个接口之前,需要先登录系统(物流WMS系统),并在登录后,选择并进入需要操作的仓库,然后请求接口,…...
MySQL跨服务器关联查询
1. 首先确认服务器的Federated引擎是否开启 show engines;修改数据库的配制文件my.ini,(我的my.ini的路径为:D:\ProgramData\MySQL\MySQL Server 5.7/my.ini),将federated添加到my.ini文件中 到MySQL的my.cnf配置文件中修改 在 [mysqld] 下方加入 federated 然后重…...
分库分表浅析
简介 对于任何系统而言,都会设计到数据库随着时间增长而累积越来越多的数据,系统也因为越来越多的需求变迁导致原有的设计不再满足现状,为了解决这些问题,分库分表就会走进视野,带着几个问题走入分库分表。 什么是分…...
java 宠物医院系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目
一、源码特点 java 宠物医院系统是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql5.0&…...
XMall 开源商城 SQL注入漏洞复现(CVE-2024-24112)
0x01 产品简介 XMall 开源电商商城 是开发者Exrick的一款基于SOA架构的分布式电商购物商城 前后端分离 前台商城:Vue全家桶 后台管理:Dubbo/SSM/Elasticsearch/Redis/MySQL/ActiveMQ/Shiro/Zookeeper等。 0x02 漏洞概述 XMall 开源商城 /item/list、/item/listSearch、/sys/…...
Docker原理及概念相关
Docker最核心的组件 image:镜像,构建容器,也可以通过Dockerfile文本描述镜像的内容。 (我们将应用程序运行所需的环境,打包为镜像文件) Container:容器 (你的应用程序,就跑在容器中 ) 镜像仓库(dockerhub)(…...
Vim相关配置
记录一下有关vim的一些设置,以免电脑寄了不好重新配置 vscodevim 首先是vscode中的vim模式 在应用商店中搜索vim插件安装即可 然后在setting中添加以下有关vim 的配置 "vim.easymotion": true,"vim.surround": true,"vim.incsearch"…...
ARMv8-AArch64 的异常处理模型详解之异常处理详解(进入异常以及异常路由)
在上篇文章 ARMv8-AArch64 的异常处理模型详解之异常处理概述Handling exceptions中,作者对异常处理整体流程以及相关概念做了梳理。接下来,本文将详细介绍处理器在获取异常、异常处理以及异常返回等过程中都做了哪些工作。 ARMv8-AArch64 的异常处理模型…...
unity学习(19)——客户端与服务器合力完成注册功能(1)入门准备
逆向服务器用了三天的时间,但此时觉得一切都值,又可以继续学习了。 服务器中登录请求和注册请求由command变量进行区分,上一层的type变量都是login。 public void process(Session session, SocketModel model) {switch (model.Command){ca…...
论文精读--对比学习论文综述
InstDisc 提出了个体判别任务,而且利用这个代理任务与NCE Loss去做对比学习从而得到了不错的无监督表征学习的结果;同时提出了别的数据结构——Memory Bank来存储大量负样本;解决如何对特征进行动量式的更新 翻译: 有监督学习的…...
文章复现 | 差异分析和PPI网络构建
原文链接:差异分析和PPI网路图绘制教程 写在前面 在原文中,作者获得285个DEG,在此推文中共获得601个DEG。小杜的猜想是标准化的水段不同的原因吧,或是其他的原因。此外,惊奇的发现发表医学类的文章在附件中都不提供相…...
入门级10寸加固行业平板—EM-I10J
亿道信息以其坚固耐用的智能终端设备而闻名,近日发布了一款理想入门级 10 英寸加固平板电脑—I10J。 EM-I10J 这是一款 10 英寸的平板电脑,主要运行 Windows 10操作系统,带有硬化塑料外壳,具有 IP65 防水防尘功能和 MIL-STD 8…...
gem5 garnet 合成流量: packet注入流程
代码流程 下图就是全部. 剩下文字部分是细节补充,但是内容不变: bash调用python,用python配置好configuration, 一个cpu每个tick运行一次,requestport发出pkt. bash 启动 python文件并配置 ./build/NULL/gem5.debug configs/example/garnet_synth_traffic.py \--num-cpus…...
java实现排序算法(上)
排序算法 冒泡排序 时间和空间复杂度 要点 每轮冒泡不断地比较比较相邻的两个元素,如果它们是逆序的,则需要交换它们的位置下一轮冒泡,可以调整未排序的右边界,减少不必要比较 代码 public static int[] test(int[] array) {// 外层循环控制遍历次数for (int i 0; i <…...
「算法」滑动窗口
前言 算法需要多刷题积累经验,所以我行文重心在于分析解题思路,理论知识部分会相对简略一些 正文 滑动窗口属于双指针,这两个指针是同向前行,它们所夹的区间就称为“窗口” 啥时候用滑动窗口? 题目涉及到“子序列…...
Windows11(非WSL)安装Installing llama-cpp-python with GPU Support
直接安装,只支持CPU。想支持GPU,麻烦一些。 1. 安装CUDA Toolkit (NVIDIA CUDA Toolkit (available at https://developer.nvidia.com/cuda-downloads) 2. 安装如下物件: gitpythoncmakeVisual Studio Community (make sure you install t…...
rtt设备io框架面向对象学习-脉冲编码器设备
目录 1.脉冲编码器设备基类2.脉冲编码器设备基类的子类3.初始化/构造流程3.1设备驱动层3.2 设备驱动框架层3.3 设备io管理层 4.总结5.使用 1.脉冲编码器设备基类 此层处于设备驱动框架层。也是抽象类。 在/ components / drivers / include / drivers 下的pulse_encoder.h定义…...
华为OD机试真题- 攀登者2-2024年OD统一考试(C卷)
题目描述: 攀登者喜欢寻找各种地图,并且尝试攀登到最高的山峰。地图表示为一维数组,数组的索引代表水平位置,数组的高度代表相对海拔高度。其中数组元素0代表地面。例如[0,1,4,3,1,0,0,1,2,3,1,2,1,0], 代表如下图所示的地图,地图中有两个山脉位置分别为 1,2,3,4,5和8,9,1…...
19.Qt 组合框的实现和应用
目录 前言: 技能: 内容: 1. 界面 2.槽 3.样式表 参考: 前言: 学习QCombox控件的使用 技能: 简单实现组合框效果 内容: 1. 界面 在ui编辑界面找到input widget里面的comboBoxÿ…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
