首页
留言
友情链接
壁纸
更多
关于
Search
1
dockerfile怎么执行shell脚本(利用tail -f /dev/null命令防止container启动后退出)
5,016 阅读
2
channel常见的异常总结
4,276 阅读
3
支付宝支付配置开发流程
1,430 阅读
4
HTTP 协议中的Content-Encoding
1,286 阅读
5
Laravel底层原理(二) —— 契约(Contracts)
950 阅读
PHP
composer
laravel
swoole
Docker
Linux
Go
随笔
mysql
nginx
Search
标签搜索
kratos
golang
微服务
gopher
PHP
Docker
dockerfile
通道
go
defer
alipay
支付
git
phpstorm
IDEA
web安全
漏洞
socket
设计原则
依赖注入
Royal
累计撰写
51
篇文章
累计收到
0
条评论
首页
栏目
PHP
composer
laravel
swoole
Docker
Linux
Go
随笔
mysql
nginx
页面
留言
友情链接
壁纸
关于
搜索到
1
篇与
依赖注入
的结果
2025-02-05
(五)kratos的依赖注入库- Wire
理解依赖注入 什么是依赖注入?为什么要依赖注入? 依赖注入 (Dependency Injection,缩写为 DI),可以理解为一种代码的构造模式(就是写法),按照这样的方式来写,能够让你的代码更加容易维护。对于很多软件设计模式和架构的理念,我们都无法理解他们要绕好大一圈做复杂的体操、用奇怪的方式进行实现的意义。他们通常都只是丢出来一段样例,说这样写就很好很优雅,由于省略掉了这种模式是如何发展出来的推导过程,我们只看到了结果,导致理解起来很困难。那么接下来我们来尝试推导还原一下整个过程,看看代码是如何和为什么演进到依赖注入模式的,以便能够更好理解使用依赖注入的意义。依赖是什么? 这里的依赖是个名词,不是指软件包的依赖(比如那坨塞在 node_modules 里面的东西),而是指软件中某一个模块(对象/实例)所依赖的其它外部模块(对象/实例)。注入到哪里? 被依赖的模块,在创建模块时,被注入到(即当作参数传入)模块的里面。Wire 依赖注入 Wire 是一个灵活的依赖注入工具,通过自动生成代码的方式在编译期完成依赖注入。在各个组件之间的依赖关系中,通常鼓励显式初始化,而不是全局变量传递。所以通过 Wire 进行初始化代码,可以很好地解决组件之间的耦合,以及提高代码维护性。安装工具# 导入到项目中 go get -u github.com/google/wire # 安装命令 go install github.com/google/wire/cmd/wire工作原理 Wire 具有两个基本概念:Provider 和 Injector。Provider 是一个普通的 Go Func ,这个方法也可以接收其它 Provider 的返回值,从而形成了依赖注入;// 提供一个配置文件(也可能是配置文件) func NewConfig() *conf.Data {...} // 提供数据组件,依赖了数据配置(初始化 Database、Cache 等) func NewData(c *conf.Data) (*Data, error) {...} // 提供持久化组件,依赖数据组件(实现 CURD 持久化层) func NewUserRepo(d *data.Data) (*UserRepo, error) {...}使用方式 在 Kratos 中,主要分为 server、service、biz、data 服务模块,会通过 Wire 进行模块顺序的初始化;在每个模块中,只需要一个 ProviderSet 提供者集合,就可以在 wire 中进行依赖注入;并且我们在每个组件提供入口即可,不需要其它依赖,例如:-data --data.go // var ProviderSet = wire.NewSet(NewData, NewGreeterRepo) --greeter.go // func NewGreeterRepo(data *Data, logger log.Logger) biz.GreeterRepo {...}然后通过 wire.go 中定义所有 ProviderSet 可以完成依赖注入配置。初始化组件 通过 wire 初始化组件,需要定义对应的 wire.go,以及 kratos application 用于启动管理。// 应用程序入口 cmd -main.go -wire.go -wire_gen.go // main.go 创建 kratos 应用生命周期管理 func newApp(logger log.Logger, hs *http.Server, gs *grpc.Server, greeter *service.GreeterService) *kratos.App { pb.RegisterGreeterServer(gs, greeter) pb.RegisterGreeterHTTPServer(hs, greeter) return kratos.New( kratos.Name(Name), kratos.Version(Version), kratos.Logger(logger), kratos.Server( hs, gs, ), ) } // wire.go 初始化模块 func initApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, error) { // 构建所有模块中的 ProviderSet,用于生成 wire_gen.go 自动依赖注入文件 panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp)) }在项目的 main 目录中,运行 wire 进行生成编译期依赖注入代码:wire总结 重新总结一下用 wire 做依赖注入的过程。 1. 定义 Injector 创建wire.go文件,定义下你最终想用的实例初始化函数例如initApp(即 Injector),定好它返回的东西*App,在方法里用panic(wire.Build(NewRedis, SomeProviderSet, NewApp))罗列出它依赖哪些实例的初始化方法(即 Provider)/或者哪些组初始化方法(ProviderSet)2. 定义 ProviderSet(如果有的话) ProviderSet 就是一组初始化函数,是为了少写一些代码,能够更清晰的组织各个模块的依赖才出现的。也可以不用,但 Injector 里面的东西就需要写一堆。 像这样 var SomeProviderSet = wire.NewSet(NewES,NewDB)定义 ProviderSet 里面包含哪些 Provider3. 实现各个 Provider Provider 就是初始化方法,你需要自己实现,比如 NewApp,NewRedis,NewMySQL,GetConfig 等,注意他们们各自的输入输出 4. 生成代码 执行 wire 命令生成代码,工具会扫描你的代码,依照你的 Injector 定义来组织各个 Provider 的执行顺序,并自动按照 Provider 们的类型需求来按照顺序执行和安排参数传递,如果有哪些 Provider 的要求没有满足,会在终端报出来,持续修复执行 wire,直到成功生成wire_gen.go文件。接下来就可以正常使用initApp来写你后续的代码了。如果需要替换实现,对 Injector 进行相应的修改,实现必须的 Provider,重新生成即可。
2025年02月05日
16 阅读
0 评论
0 点赞