内容简介:Go团队最近公布了用于开放云开发的可移植云API和工具,开源项目依赖注入是一种编写可伸缩、低耦合代码的标准技术。因为依赖注入显式地为组件提供他们需要工作的所有依赖关系。 在Go中,这通常采用将依赖项传递给构造函数的形式:这种技术在小规模下工作得很好,但是较大的应用程序会存在一个复杂的依赖图。这导致了一大块依赖于顺序的初始化代码,这并不好玩。 因为一些依赖项被多次使用,通常很难干净地拆分这些代码。 将服务的一个实现替换为另一个实现也会很痛苦,因为这涉及到通过添加一组全新的依赖项(及其依赖项...)来修改依赖
Go团队最近公布了用于开放云开发的可移植云API和工具,开源项目 Go Cloud 。 这篇文章详细介绍了Wire,一个随Go Cloud提供的依赖注入工具。
Wire解决了什么问题?
依赖注入是一种编写可伸缩、低耦合代码的标准技术。因为依赖注入显式地为组件提供他们需要工作的所有依赖关系。 在 Go 中,这通常采用将依赖项传递给构造函数的形式:
// NewUserStore返回一个使用cfg和db作为依赖项的UserStore。 func NewUserStore(cfg *Config, db *mysql.DB) (*UserStore, error) {...} 复制代码
这种技术在小规模下工作得很好,但是较大的应用程序会存在一个复杂的依赖图。这导致了一大块依赖于顺序的初始化代码,这并不好玩。 因为一些依赖项被多次使用,通常很难干净地拆分这些代码。 将服务的一个实现替换为另一个实现也会很痛苦,因为这涉及到通过添加一组全新的依赖项(及其依赖项...)来修改依赖项图,并删除未使用的旧项。 实际上,在具有庞大依赖图的应用程序中更改初始化代码是繁琐且缓慢的。
像Wire这样的依赖注入 工具 旨在简化初始化代码的管理。您可以将您的服务及其依赖关系描述为代码或配置,然后Wire处理生成关系图,再据此确定初始化 排序 以及如何向每个服务传递它所需的依赖。 通过更改函数签名、添加或删除初始化程序来更改应用程序的依赖项,然后让Wire执行为整个依赖图生成初始化代码的繁琐工作。
为什么这是Go Cloud的一部分?
Go Cloud的目标是通过为合适的云服务提供惯用的Go API,使编写便携式云应用程序变得更加容易。 例如, blob.Bucket
提供了一个存储API,其中包含亚马逊S3和谷歌云存储(GCS)的实现; 使用 blob.Bucket
编写的应用程序可以交换实现而无需更改其应用程序逻辑。 但是,初始化代码本质上是特定于提供者的,并且每个提供者具有不同的依赖集。
例如,
构建GCS blob.Bucket
需要 gcp.HTTPClient
,最终需要 google.Credentials
,而 为S3构建一个
则需要 aws.Config
,最终需要AWS凭据。 因此,更新应用程序以使用不同的 blob.Bucket
实现涉及到我们上面描述的依赖关系图的那种繁琐的更新。 Wire的驱动用例是为了方便交换Go Cloud可移植API的实现,但同时它也是依赖注入的通用工具。
这些工作不是已经做过了吗?
确实有许多依赖注入框架。对Go来说, Uber的dig 和 Facebook的inject 都使用反射来进行运行时依赖注入。 Wire的主要灵感来自 Java 的Dagger 2 ,并且使用代码生成而不是反射或服务定位器 。
我们认为这种方法有几个优点:
- 当依赖关系图变得复杂时,运行时依赖注入很难跟踪和调试。 使用代码生成意味着在运行时执行的初始化代码是常规的,惯用的Go代码,易于理解和调试。不会因为框架的各种奇技淫巧而变得生涩难懂。特别重要的是,忘记依赖项等问题会成为编译时错误,而不是运行时错误。
- 与服务定位器不同,不需要费心编造名称来注册服务。 Wire使用Go语法中的类型将组件与其依赖项连接起来。
- 更容易防止依赖项变得臃肿。 Wire生成的代码只会导入您需要的依赖项,因此您的二进制文件将不会有未使用的导入。 运行时依赖性注入器在运行之前无法识别未使用的依赖项。
- Wire的依赖图是静态可知的,这为工具化和可视化提供了可能。
它是如何工作的?
Wire有两个基本概念:提供者和注射器。
提供者 是普通的Go函数,它们根据它们的依赖关系“提供”值,这些值被简单地描述为函数的参数。 以下是一些定义三个提供程序的示例代码:
// NewUserStore与我们上面看到的功能相同; 它是UserStore的提供者, //依赖于*Config和*mysql.DB。 func NewUserStore(cfg *Config, db *mysql.DB) (*UserStore, error) {...} // NewDefaultConfig是*Config的提供者,没有依赖。 func NewDefaultConfig() *Config {...} // NewDB是基于某些连接信息的* mysql.DB的提供者。 func NewDB(info *ConnectionInfo) (*mysql.DB, error) {...} 复制代码
通常一起使用的 ProviderSets
可以分组到 ProviderSets
。 例如,在创建 *UserStore
时使用默认的 *Config
是很常见的,因此我们可以在 ProviderSet
中对 NewUserStore
和 NewDefaultConfig
进行分组:
var UserStoreSet = wire.ProviderSet(NewUserStore, NewDefaultConfig) 复制代码
注入器
是被生成的函数,它们按依赖所需的顺序调用提供者。 编写注入器的签名,包括任何所需的输入作为参数,并插入对 wire.Build
的调用, wire.Build
包含构造最终结果所需的提供者或提供者集的列表:
func initUserStore() (*UserStore, error) { //我们将得到一个错误,因为NewDB需要一个*ConnectionInfo //我们没有提供。 wire.Build(UserStoreSet, NewDB) return nil, nil // 这些返回值会被忽略。 } 复制代码
现在我们运行go generate来执行wire:
$ go generate wire.go:2:10: inject initUserStore: no provider found for ConnectionInfo (required by provider of *mysql.DB) wire: generate failed 复制代码
哎呀! 我们没有包含 ConnectionInfo
也没有告诉Wire如何构建一个。 Wire有用地告诉我们涉及的行号和类型。 我们可以将它的提供者添加到 wire.Build
,或者将其添加为参数:
func initUserStore(info ConnectionInfo) (*UserStore, error) { wire.Build(UserStoreSet, NewDB) return nil, nil // 这些返回值会被忽略。 } 复制代码
现在 go generate
将使用生成的代码创建一个新文件:
// File: wire_gen.go // Code generated by Wire. DO NOT EDIT. //go:generate wire //+build !wireinject func initUserStore(info ConnectionInfo)(* UserStore,error){ defaultConfig:= NewDefaultConfig() db,err:= NewDB(info) if err!= nil { return nil, err } userStore,err:= NewUserStore(defaultConfig,db) if err!= nil { return nil, err } return userStore,nil } 复制代码
任何非注入器声明都将复制到生成的文件中。 在运行时没有依赖Wire:所有编写的代码都是正常的Go代码。
如您所见,输出非常接近开发人员自己编写的内容。 这只是一个简单的例子,只有三个组件,因此手工编写初始化程序并不会太痛苦,但Wire为具有更复杂依赖关系图的组件和应用程序节省了大量的手工操作。
我如何参与并了解更多信息?
Wire README 详细介绍了如何使用Wire及其更高级的功能。 还有一个 教程 可以在一个简单的应用程序中使用Wire。
感谢您对Wire使用体验的任何意见! Go Cloud的 开发是在GitHub上进行的,所以你可以 提出一个问题 来告诉我们什么可能更好。 有关项目的更新和讨论,请加入项目的邮件列表 。
感谢您抽出宝贵时间了解Go Cloud的Wire。 我们很高兴与您合作,使Go成为构建可移植云应用程序的开发人员的首选语言。
作者:Robert van Gent
原文:blog.golang.org/wire
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Angular 4 依赖注入教程之二 组件中注入服务
- 服务端注入之Flask框架中服务端模板注入问题
- 服务器端电子表格注入 - 从公式注入到远程代码执行
- SQL注入测试技巧TIP:再从Mysql注入绕过过滤说起
- 手机抓包+注入黑科技HttpCanary——最强大的Android抓包注入工具
- 三, 跨语言微服务框架 - Istio官方示例(自动注入.请求路由.流量控制.故障注入) 原 荐
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Programming Computer Vision with Python
Jan Erik Solem / O'Reilly Media / 2012-6-22 / USD 39.99
If you want a basic understanding of computer vision's underlying theory and algorithms, this hands-on introduction is the ideal place to start. As a student, researcher, hacker, or enthusiast, you'll......一起来看看 《Programming Computer Vision with Python》 这本书的介绍吧!