依赖注入的正确打开方式 bilibili/kratos × google/wire
一、前言
依赖注入相信大家都不陌生也不是什么新鲜的概念了,笔者初次深切体会依赖注入这种设计模式是在16年笔者在学习phalapi框架时使用的DI()函数,简单来说就是将所有的资源初始化集中在一起,通过统一的容器对外提供,而不是通过全局变量或到处New的方式。最近在学习kratos又看到一个团队的历史项目都使用wier,一个是正面教材一个是反面教材也有一些自己的思考,希望能够分享出来和大家交流交流。
资料如下:
- wier官方文档:https://github.com/google/wire
- kratos依赖注入:https://go-kratos.dev/docs/guide/wire
- phalapi依赖注入:http://www.phalapi.net/wikis/2-11.html
二、依赖注入解决什么问题?
其实笔者开始写Goalng包括团队内部自己研发的小框架go-core主要使用的是资源容器的方式,框架帮助你将资源统一的容器管理起来(也是一种间接的全局变量的方式,只是不能直接进行修改),但对于业务分层如果是微服务的话足够简单就直接 packagename.funcname 进行调用,如果是稍微复杂一些的项目用一个空的status的全局变量来提供func的隔离。
但这样的设计会存在一下几个问题:
- 依赖不清晰:
- 虽然限定了调用层级,但无法直观了解当前模块依赖那些下层模块
- 资源获取僵化不灵活:
- 资源获取在最底层虽然可以也实现多态,但影响范围只能是全局,无法控制作用域
- 避免犯错:
- 无论是容器资源管理还是全局status变量都存在被误操作的可能性
三、一个糟糕的依赖注入的设计
如果你使用成熟框架无论是go-zero或kratos都应该按照他们的最佳实践来执行,如果是框架层没有约束还是要更具自己的实际情况来进行选择,有限选择最简单的方式顺应研发人员的直觉,设计模式如果用不对那将是场灾难,就和最近接触到了一个项目虽然使用了wier作为依赖注入,但是用的一塌糊涂:
它存在的问题:
- 貌似依赖注入了又貌似没有
- 一个大对象实例化了保管了所有资源
- 获取资源还是在使用New的方式
- 应为需要New所以下次实例化需要的资源也变成了当前这一层的依赖,需要一层一层将资源传递下去
- 所有入口资源都依赖了一个全局的大资源
一个设计模式如果没有用对,虽然解决了上面资源共享的问题,但是又带来了一堆奇怪的问题,真的是得不偿失。所以架构也好业务也好都是逐步演进过来的,不要将设计模式当做万能药,第一性原则还是保持简单和高内聚低耦合,遇到文件引入对应的方案然后需要做好落地的最佳实践。
四、怎样是一个好的依赖注入?
当笔者接触到上面的项目之后就非常的迷茫,在思考怎么样才是一个好的依赖注入设计模式的落地呢?当接触到 kratos 之后给了我一些启发:
一个好的依赖注入需要具备哪些特性
- 编码过程中所有的依赖都只能从自身对象实例中获取,不允许New或使用全局变量
- 依赖注入过程要贯穿全流程,从grpc服务或http服务初始化开始而不是从业务才开始使用
bilibili/kratos × google/wire 标准样例:
// 定义依赖关系,从头到尾
func wireApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) {panic(wire.Build(server.ProviderSet,data.ProviderSet,biz.ProviderSet,service.ProviderSet,newApp))
}// 初始化方法也要参与依赖注入
func newApp(logger log.Logger, gs *grpc.Server, hs *http.Server) *kratos.App {return kratos.New(kratos.ID(id),kratos.Name(Name),kratos.Version(Version),kratos.Metadata(map[string]string{}),kratos.Logger(logger),kratos.Server(gs,hs,),)
}// 程序启动直接从wier生成的方法中获取app, cleanup, err := wireApp(bc.Server, bc.Data, logger)if err != nil {panic(err)}defer cleanup()// start and wait for stop signalif err := app.Run(); err != nil {panic(err)}
依赖的资源都是局部的,并且只关注自己所依赖的范围,依赖的依赖怎么注入不应该被关注
// GreeterService is a greeter service.
type GreeterService struct {v1.UnimplementedGreeterServeruc *biz.GreeterUsecase
}// NewGreeterService new a greeter service.
func NewGreeterService(uc *biz.GreeterUsecase) *GreeterService {return &GreeterService{uc: uc}
}...
// GreeterUsecase is a Greeter usecase.
type GreeterUsecase struct {repo GreeterRepolog *log.Helper
}// NewGreeterUsecase new a Greeter usecase.
func NewGreeterUsecase(repo GreeterRepo, logger log.Logger) *GreeterUsecase {return &GreeterUsecase{repo: repo, log: log.NewHelper(logger)}
}
依赖注入的正确打开方式 bilibili/kratos × google/wire相关推荐
- opengl 贴图坐标控制_材质贴图正确打开方式
哈喽,各位观众朋友们好鸭~欢迎来到讲道理画图的地方,我是黄玮宁. 最近呀经常有小伙伴来问我那些不同通道的材质贴图该怎么用,而且频率不是一般的高,所以我觉得有必要来说说这些通道贴图的用法了. 视频版(B ...
- 通过机器学习识别“迪士尼在逃公主”,程序员宠女的正确打开方式!
到了庆祝的时候了!我们刚刚送走了圣诞老人.现在正等待新年的钟声敲响.所以我想到建立一个很酷的东西(至少我的七岁小公主会觉得)同时学一点机器学习.所以我们要做一个什么? 我借用的我女儿所有迪士尼公主人偶 ...
- [分布式训练] 单机多卡的正确打开方式:理论基础
[分布式训练] 单机多卡的正确打开方式:理论基础 转自:https://fyubang.com/2019/07/08/distributed-training/ 瓦砾由于最近bert-large用的比 ...
- 拜托!这才是分布式系统CAP的正确打开方式!
"纸面"上的CAP 相信很多同学都听过CAP这个理论,为了避免我们认知不同,我们先来统一下知识起点. CAP理论在1999年一经提出就成为了分布式系统领域的顶级教义.并表明分布式服 ...
- lambda学习视频和stream学习视频(Java8 Lambda表达式视频教程)-Java爬虫-网络购物的正确打开方式
百度网盘 链接:https://pan.baidu.com/s/1upU5EVXOQeho6poDYdnhiQ 提取码:088l Java8 Lambda表达式视频教程 https://www.bil ...
- Spring系列之依赖注入的三种方式
目录 一.依赖注入方式 1.使用属性的setXXX方法注入 2.构造函数注入 (1)按类型匹配入参type (2)按索引匹配入参index (3)联合使用类型和索引匹配入参[type和index一起使 ...
- 肖秀荣、陆寓丰、徐涛三大名师的正确“打开方式”
考研政治怎么学? 肖秀荣.陆寓丰.徐涛 三大名师的正确"打开方式" HEY 暑假黄金期到达尾声,是不是有很多小伙伴还没有开始政治复习?或者复习的迷迷糊糊? 今天笔者会为大家进行全面 ...
- 二次元的正确打开方式
本文 GitHub https://github.com/Jack-Cherish/PythonPark 已收录,有技术干货文章,整理的学习资料,一线大厂面试经验分享等,欢迎 Star 和 完善. 一 ...
- android动态设置错误页面,Android缺省页的正确打开方式(优雅的处理loading、error、empty...
Android缺省页的正确打开方式(优雅的处理loading.error.empty Android缺省页的正确打开方式(优雅的处理loading.error.empty各种状态缺省) MultiSt ...
最新文章
- mysql sleep详解_mysql sleep链接过多的原因及解决办法
- 5G信令(就是用户身份信息)——手机开机后,先从USIM中读取之前运营商分配的临时身份信息GUTI/TMSI,发送携带该身份信息的信令给基站,请求接入运营商网络。...
- python是动态类型语言、变量不需要显示声明类型_【IT专家】第3章 Python基础
- matlab中句柄图性对像的设置
- 【MM模块】Source Lists 货源清单
- HP LoadRunner 12.02 Tutorial T7177-88037教程独家中文版
- YbtOJ#883-最大的割【带修线性基】
- 前端学习(1687):前端系列javascript基础面试前言
- uniapp ajax数据库查询,uniapp小程序登录、数据请求方式
- 根据list中某个字段的值排序_MySql中常用函数
- 《机器学习实战》学习总结(五)K-means算法原理
- 会畅通讯登陆创业板上市,CEO黄元庚说云视频是下一个万亿级市场
- 基于SSH框架社区智能化管理系统答辩PPT模板
- 教你定时爬取微博热搜榜并做动态数据展示,让你不错过任何一个吃瓜热点
- python3.6+Appium实现手机微信自动回复
- python零基础教学plc_Python从基础到开发精修全面学习视频教程
- github+gitee上传源码 git工具的安装和使用
- ndows movie maker,Windows Movie Maker
- 用U盘安装Windows server 2012 R2
- javascript 图片特效算法
热门文章
- Deepin Linux15 华为荣耀笔记本MagicBook2019使用-安装深度应用商店和应用软件
- crontab 每5秒钟执行一次
- PHP 将xml文件解析为数组
- TDSQL-C PostgreSQL(CynosDB) 内核解密-披荆斩棘,勇往直前的腾讯云数据库
- 解决Maven:Cannot resolve com.oracle.ojdbc:ojdbc6:11.2.0.1.0报红找不到问题,解决方案亲测有效详细图文教程 问题描述
- 转行程序员日记--2020-08-10
- bread是可数还是不可数_bread可数吗
- 【华为云技术分享】华为云弹性云服务器ECS搭建FTP服务实践
- google map v3离线版地图
- python爬取股市数据