go依赖注入dig包使用-来自uber公司原文链接:
github:
Dependency Injection is the idea that your components (usuallystructsin go) should receive their dependencies when being created. This runs counter to the associated anti-pattern of components building their own dependencies during initialization. Let’s look at an example.
Suppose you have aServerstruct that requires aConfigstruct to implement its behavior. One way to do this would be for theServerto build its ownConfigduring initialization.
This seems convenient. Our caller doesn’t have to be aware that ourServereven needs access toConfig . This is all hidden from the user of our function.
However, there are some disadvantages. First of all, if we want to change the way ourConfigis built, we’ll have to change all the places that call the building code. Suppose, for example, ourbuildMyConfigSomehowfunction now needs an argument. Every call site would need access to that argument and would need to pass it into the building function.
Also, it gets really tricky to mock the behavior of ourConfig . We’ll somehow have to reach inside of ourNewfunction to monkey with the creation ofConfig .
Here’s the DI way to do it:
Now the creation of ourServeris decoupled from the creation of theConfig . We can use whatever logic we want to create theConfigand then pass the resulting data to ourNewfunction.
Furthermore, ifConfigis an interface, this gives us an easy route to mocking. We can pass anything we want intoNewas long as it implements our interface. This makes testing ourServerwith mock implementations ofConfigsimple.
The main downside is that it’s a pain to have to manually create theConfigbefore we can create theServer . We’ve created a dependency graph here – we must create ourConfigfirst because ofServerdepends on it. In real applications these dependency graphs can become very large and this leads to complicated logic for building all of the components your application needs to do its job.
This is where DI frameworks can help. A DI framework generally provides two pieces of functionality:
A DI framework generally builds a graph based on the “providers” you tell it about and determines how to build your objects. This is very hard to understand in the abstract, so let’s walk through a moderately-sized example.
We’re going to be reviewing the code for an HTTP server that delivers a JSON response when a client makes aGETrequest to/people . We’ll review the code piece by piece. For simplicity sake, it all lives in the same package ( main ). Please don’t do this in real Go applications. Full code for this example can be foundhere .
First, let’s look at ourPersonstruct. It has no behavior save for some JSON tags.
APersonhas anId ,NameandAge . That’s it.
Next let’s look at ourConfig . Similar toPerson , it has no dependencies. UnlikePerson , we will provide a constructor.
Enabledtells us if our application should return real data.DatabasePathtells us where our database lives (we’re using sqlite).Porttells us the port on which we’ll be running our server.
Here’s the function we’ll use to open our database connection. It relies on ourConfigand returns a*sql.DB .
Next we’ll look at ourPersonRepository . This struct will be responsible for fetching people from our database and deserializing those database results into properPersonstructs.
PersonRepositoryrequires a database connection to be built. It exposes a single function calledFindAllthat uses our database connection to return a list ofPersonstructs representing the data in our database.
To provide a layer between our HTTP server and thePersonRepository , we’ll create aPersonService .
OurPersonServicerelies on both theConfigand thePersonRepository . It exposes a function calledFindAllthat conditionally calls thePersonRepositoryif the application is enabled.
Finally, we’ve got ourServer . This is responsible for running an HTTP server and delegating the appropriate requests to ourPersonService .
TheServeris dependent on thePersonServiceand theConfig .
Ok, we know all the components of our system. Now how the hell do we actually initialize them and start our system?
First, let’s write ourmain()function the old fashioned way.
First, we create ourConfig . Then, using theConfig , we create our database connection. From there we can create ourPersonRepositorywhich allows us to create ourPersonService . Finally, we can use this to create ourServerand run it.
Phew, that was complicated. Worse, as our application becomes more complicated, ourmainwill continue to grow in complexity. Every time we add a new dependency to any of our components, we’ll have to reflect that dependency with ordering and logic in themainfunction to build that component.
As you might have guessed, a Dependency Injection framework can help us solve this problem. Let’s examine how.
The term “container” is often used in DI frameworks to describe the thing into which you add “providers” and out of which you ask for fully-build objects. Thediglibrary gives us theProvidefunction for adding providers and theInvokefunction for retrieving fully-built objects out of the container.
First, we build a new container.
Now we can add new providers. To do so, we call theProvidefunction on the container. It takes a single argument: a function. This function can have any number of arguments (representing the dependencies of the component to be created) and one or two return values (representing the component that the function provides and optionally an error).
【go语言注入工具 go语言import】 The above code says “I provide aConfigtype to the container. In order to build it, I don’t need anything else.” Now that we’ve shown the container how to build aConfigtype, we can use this to build other types.
This code says “I provide a*sql.DBtype to the container. In order to build it, I need aConfig . I may also optionally return an error.”
In both of these cases, we’re being more verbose than necessary. Because we already haveNewConfigandConnectDatabasefunctions defined, we can use them directly as providers for the container.
Now, we can ask the container to give us a fully-built component for any of the types we’ve provided. We do so using theInvokefunction. TheInvokefunction takes a single argument – a function with any number of arguments. The arguments to the function are the types we’d like the container to build for us.
The container does some really smart stuff. Here’s what happens:
That’s a lot of work the container is doing for us. In fact, it’s doing even more. The container is smart enough to build one, and only one, instance of each type provided. That means we’ll never accidentally create a second database connection if we’re using it in multiple places (say multiple repositories).
Now that we know how thedigcontainer works, let’s use it to build a better main.
The only thing we haven’t seen before here is theerrorreturn value fromInvoke . If any provider used byInvokereturns an error, our call toInvokewill halt and that error will be returned.
Even though this example is small, it should be easy to see some of the benefits of this approach over our “standard” main. These benefits become even more obvious as our application grows larger.
One of the most important benefits is the decoupling of the creation of our components from the creation of their dependencies. Say, for example, that ourPersonRepositorynow needs access to theConfig . All we have to do is change ourNewPersonRepositoryconstructor to include theConfigas an argument. Nothing else in our code changes.
Other large benefits are lack of global state, lack of calls toinit(dependencies are created lazily when needed and only created once, obviating the need for error-proneinitsetup) and ease of testing for individual components. Imagine creating your container in your tests and asking for a fully-build object to test. Or, create an object with mock implementations of all dependencies. All of these are much easier with the DI approach.
I believe Dependency Injection helps build more robust and testable applications. This is especially true as these applications grow in size. Go is well suited to building large applications and has a great DI tool indig . I believe the Go community should embrace DI and use it in far more applications.
go语言有类似javaagent的工具吗没有 。
go语言开发工具有:Gogland、Eclipse、LiteIDE、KomodoIDE、Atom、Brackets、VisualStudioCode、Cloud9、CodeEnv、Wide等等 。
golang语言并没有提供类似javaagent的机制允许我们在程序运行中修改代码逻辑 。
Go语言怎么样?根据Go趋势报告显示,全球范围内有 110 万专业开发者选择Go作为其主要开发语言 。如果把以其他编程语言作为主要开发语言,同时也在使用Go的开发者计算在内,这一数字将高达270万,中国的Go语言开发者排名第一,全球占比超过16% 。
Go 语言能够支持并构建与微服务结合的内部工具、架构和后端服务而深受IT企业欢迎,许多IT架构工具由Go构建而成 , 例如大型的Kubernetes、Docker和Vault等 。数据显示,有63%的具有统治力的云原生项目都是用Go构建 。
因此 , 博睿数据在国内首发支持Go语言智能探针,对于提升业务性能,助力企业数字化转型有着非常重要的意义 。
SmartAgent探针技术集结主流编程语言
SmartAgent是博睿数据自研的自动化部署的一体化探针,在已支持JAVA,PHP,.net,Nodejs,.NET Core,Python的基础上,新增了对Go语言的支持 。
相较而言 , 传统探针技术需要客户配合修改应用程序代码,风险不可控,需要客户重新编译程序集成探针 , 耦合度高 。
不同于行业内传统探针技术,博睿数据GoAgent探针直接后台安装即可,主动注入和嵌码,降低与客户程序耦合、无需二次修改代码、提高 GoAgent 技术易用性 。无论是动态编译还是静态编译的代码 , 博睿数据Samrt Agent技术都可以在不进行任何修改的情况下进行服务级别和代码级别的分布式链路跟踪,实现业务的可观测性 。
GoAgent探针支持六大功能,实现全链路追踪
golang反射框架FxFx是一个golang版本go语言注入工具的依赖注入框架 , 它使得golang通过可重用、可组合的模块化来构建golang应用程序变得非常容易,可直接在项目中添加以下内容即可体验Fx效果 。
Fx是通过使用依赖注入的方式替换了全局通过手动方式来连接不同函数调用的复杂度,也不同于其他的依赖注入方式,Fx能够像普通golang函数去使用,而不需要通过使用struct标签或内嵌特定类型 。这样使得Fx能够在很多go的包中很好的使用 。
接下来会提供一些Fx的简单demo,并说明其中的一些定义 。
1、一般步骤
大致的使用步骤就如下 。下面会给出一些完整的demo
2、简单demo
将io.reader与具体实现类关联起来
输出:
3、使用struct参数
前面的使用方式一旦需要进行注入的类型过多,可以通过struct参数方式来解决
输出
如果通过Provide提供构造函数是生成相同类型会有什么问题?换句话也就是相同类型拥有多个值呢go语言注入工具?
下面两种方式就是来解决这样的问题 。
4、使用struct参数 Name标签
在Fx未使用Name或Group标签时不允许存在多个相同类型的构造函数,一旦存在会触发panic 。
输出
上面通过Name标签即可完成在Fx容器注入相同类型
5、使用struct参数 Group标签
使用group标签同样也能完成上面的功能
输出
基本上Fx简单应用在上面的例子也做了简单讲解
1、Annotated(位于annotated.go文件) 主要用于采用annotated的方式,提供Provide注入类型
源码中Name和Group两个字段与前面提到的Name标签和Group标签是一样的,只能选其一使用
2、App(位于app.go文件) 提供注入对象具体的容器、LiftCycle、容器的启动及停止、类型变量及实现类注入和两者映射等操作
至于Provide和Populate的源码相对比较简单易懂在这里不在描述
具体源码
3、Extract(位于extract.go文件)
主要用于在application启动初始化过程通过依赖注入的方式将容器中的变量值来填充给定的struct,其中target必须是指向struct的指针,并且只能填充可导出的字段(golang只能通过反射修改可导出并且可寻址的字段),Extract将被Populate代替 。具体源码
4、其他
诸如Populate是用来替换Extract的,而LiftCycle和inout.go涉及内容比较多后续会单独提供专属文件说明 。
在Fx中提供的构造函数都是惰性调用,可以通过invocations在application启动来完成一些必要的初始化工作:fx.Invoke(function); 通过也可以按需自定义实现LiftCycle的Hook对应的OnStart和OnStop用来完成手动启动容器和关闭 , 来满足一些自己实际的业务需求 。
Fx框架源码解析
主要包括app.go、lifecycle.go、annotated.go、populate.go、inout.go、shutdown.go、extract.go(可以忽略,了解populate.go)以及辅助的internal中的fxlog、fxreflect、lifecycle
go语言注入工具的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于go语言import、go语言注入工具的信息别忘了在本站进行查找喔 。
推荐阅读
- 直播回放不用电脑可以吗,直播回放不用电脑可以吗怎么弄
- 小模拟拟器下载ios,小巧模拟器
- 游乐园小吃如何营销,游乐园经营什么小吃赚钱
- 虎牙宽宽跳舞直播回放下载,上海敏维软件技术有限公司
- linux命令路径查找 linux 文件路径查找
- mysql密码是什么,mysql的密码忘了该怎么办
- 关于角色扮演游戏不同角色不同故事的信息
- 策略养成游戏知乎,策略养成游戏知乎小说
- c语言函数求幂ab次方 c语言如何计算幂次