您的位置:

golang依赖注入框架,golang 依赖包

本文目录一览:

go依赖注入dig包使用-来自uber公司

原文链接:

github:

Dependency Injection is the idea that your components (usually structs in 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 a Server struct that requires a Config struct to implement its behavior. One way to do this would be for the Server to build its own Config during initialization.

This seems convenient. Our caller doesn’t have to be aware that our Server even needs access to Config . 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 our Config is built, we’ll have to change all the places that call the building code. Suppose, for example, our buildMyConfigSomehow function 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 our Config . We’ll somehow have to reach inside of our New function to monkey with the creation of Config .

Here’s the DI way to do it:

Now the creation of our Server is decoupled from the creation of the Config . We can use whatever logic we want to create the Config and then pass the resulting data to our New function.

Furthermore, if Config is an interface, this gives us an easy route to mocking. We can pass anything we want into New as long as it implements our interface. This makes testing our Server with mock implementations of Config simple.

The main downside is that it’s a pain to have to manually create the Config before we can create the Server . We’ve created a dependency graph here – we must create our Config first because of Server depends 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 a GET request 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 found here .

First, let’s look at our Person struct. It has no behavior save for some JSON tags.

A Person has an Id , Name and Age . That’s it.

Next let’s look at our Config . Similar to Person , it has no dependencies. Unlike Person , we will provide a constructor.

Enabled tells us if our application should return real data. DatabasePath tells us where our database lives (we’re using sqlite). Port tells 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 our Config and returns a *sql.DB .

Next we’ll look at our PersonRepository . This struct will be responsible for fetching people from our database and deserializing those database results into proper Person structs.

PersonRepository requires a database connection to be built. It exposes a single function called FindAll that uses our database connection to return a list of Person structs representing the data in our database.

To provide a layer between our HTTP server and the PersonRepository , we’ll create a PersonService .

Our PersonService relies on both the Config and the PersonRepository . It exposes a function called FindAll that conditionally calls the PersonRepository if the application is enabled.

Finally, we’ve got our Server . This is responsible for running an HTTP server and delegating the appropriate requests to our PersonService .

The Server is dependent on the PersonService and the Config .

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 our main() function the old fashioned way.

First, we create our Config . Then, using the Config , we create our database connection. From there we can create our PersonRepository which allows us to create our PersonService . Finally, we can use this to create our Server and run it.

Phew, that was complicated. Worse, as our application becomes more complicated, our main will 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 the main function 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. The dig library gives us the Provide function for adding providers and the Invoke function 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 the Provide function 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).

The above code says “I provide a Config type to the container. In order to build it, I don’t need anything else.” Now that we’ve shown the container how to build a Config type, we can use this to build other types.

This code says “I provide a *sql.DB type to the container. In order to build it, I need a Config . I may also optionally return an error.”

In both of these cases, we’re being more verbose than necessary. Because we already have NewConfig and ConnectDatabase functions 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 the Invoke function. The Invoke function 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 the dig container works, let’s use it to build a better main.

The only thing we haven’t seen before here is the error return value from Invoke . If any provider used by Invoke returns an error, our call to Invoke will 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 our PersonRepository now needs access to the Config . All we have to do is change our NewPersonRepository constructor to include the Config as an argument. Nothing else in our code changes.

Other large benefits are lack of global state, lack of calls to init (dependencies are created lazily when needed and only created once, obviating the need for error-prone init setup) 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 in dig . I believe the Go community should embrace DI and use it in far more applications.

GoLang -- Gin框架

• 何为框架:

框架一直是敏捷开发中的利器,能让开发者很快的上手并做出应用,甚至有的时候,脱离了框架,一些开发者都不会写程序了。成长总不会一蹴而就,从写出程序获取成就感,再到精通框架,快速构造应用,当这些方面都得心应手的时候,可以尝试改造一些框架,或是自己创造一个。

Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,已经发布了1.0版本。具有快速灵活,容错方便等特点。其实对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单,性能也非常不错。框架更像是一些常用函数或者工具的集合。借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。

(1)首先需要安装,安装比较简单,使用go get即可

go get github.com/gin-gonic/gin

如果安装失败,直接去Github clone下来,放置到对应的目录即可。

(2)代码中使用:

下面是一个使用Gin的简单例子:

package main

import (

"github.com/gin-gonic/gin"

)

func main() {

router := gin.Default()

router.GET("/ping", func(c *gin.Context) {

c.JSON(200, gin.H{

"message": "pong",

})

})

router.Run(":8080") // listen and serve on 0.0.0.0:8080

}

简单几行代码,就能实现一个web服务。使用gin的Default方法创建一个路由handler。然后通过HTTP方法绑定路由规则和路由函数。不同于net/http库的路由函数,gin进行了封装,把request和response都封装到gin.Context的上下文环境。最后是启动路由的Run方法监听端口。麻雀虽小,五脏俱全。当然,除了GET方法,gin也支持POST,PUT,DELETE,OPTION等常用的restful方法。

Gin可以很方便的支持各种HTTP请求方法以及返回各种类型的数据,详情可以前往查看。

2.1 匹配参数

我们可以使用Gin框架快速的匹配参数,如下代码所示:

冒号:加上一个参数名组成路由参数。可以使用c.Param的方法读取其值。当然这个值是字串string。诸如/user/rsj217,和/user/hello都可以匹配,而/user/和/user/rsj217/不会被匹配。

浏览器输入以下测试:

返回结果为:

其中c.String是gin.Context下提供的方法,用来返回字符串。

其中c.Json是gin.Context下提供的方法,用来返回Json。

下面我们使用以下gin提供的Group函数,方便的为不同的API进行分类。

我们创建了一个gin的默认路由,并为其分配了一个组 v1,监听hello请求并将其路由到视图函数HelloPage,最后绑定到 0.0.0.0:8000

C.JSON是Gin实现的返回json数据的内置方法,包含了2个参数,状态码和返回的内容。http.StatusOK代表返回状态码为200,正文为{"message": “welcome"}。

注:Gin还包含更多的返回方法如c.String, c.HTML, c.XML等,请自行了解。可以方便的返回HTML数据

我们在之前的组v1路由下新定义一个路由:

下面我们访问

可以看到,通过c.Param(“key”)方法,Gin成功捕获了url请求路径中的参数。同理,gin也可以捕获常规参数,如下代码所示:

在浏览器输入以下代码:

通过c.Query(“key”)可以成功接收到url参数,c.DefaultQuery在参数不存在的情况下,会由其默认值代替。

我们还可以为Gin定义一些默认路由:

这时候,我们访问一个不存在的页面:

返回如下所示:

下面我们测试在Gin里面使用Post

在测试端输入:

附带发送的数据,测试即可。记住需要使用POST方法.

继续修改,将PostHandler的函数修改如下

测试工具输入:

发送的内容输入:

返回结果如下:

备注:此处需要指定Content-Type为application/x-www-form-urlencoded,否则识别不出来。

一定要选择对应的PUT或者DELETE方法。

Gin框架快速的创建路由

能够方便的创建分组

支持url正则表达式

支持参数查找(c.Param c.Query c.PostForm)

请求方法精准匹配

支持404处理

快速的返回给客户端数据,常用的c.String c.JSON c.Data

golang反射框架Fx

Fx是一个golang版本的依赖注入框架,它使得golang通过可重用、可组合的模块化来构建golang应用程序变得非常容易,可直接在项目中添加以下内容即可体验Fx效果。

Fx是通过使用依赖注入的方式替换了全局通过手动方式来连接不同函数调用的复杂度,也不同于其他的依赖注入方式,Fx能够像普通golang函数去使用,而不需要通过使用struct标签或内嵌特定类型。这样使得Fx能够在很多go的包中很好的使用。

接下来会提供一些Fx的简单demo,并说明其中的一些定义。

1、一般步骤

大致的使用步骤就如下。下面会给出一些完整的demo

2、简单demo

将io.reader与具体实现类关联起来

输出:

3、使用struct参数

前面的使用方式一旦需要进行注入的类型过多,可以通过struct参数方式来解决

输出

如果通过Provide提供构造函数是生成相同类型会有什么问题?换句话也就是相同类型拥有多个值呢?

下面两种方式就是来解决这样的问题。

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

golang 有哪些比较稳定的 web 开发框架

第一个:Beego框架

Beego框架是astaxie的GOWeb开发的开源框架。Beego框架最大的特点是由八个大的基础模块组成,八大基础模块的特点是可以根据自己的需要进行引入,模块相互独立,模块之间耦合性低。

相应的Beego的缺点就是全部使用时比较臃肿,通过bee工具来构建项目时,直接生成项目目录和耦合关系,从而会导致在项目开发过程中受制性较大。

第二个:Gin框架

Gin是一个GOlang的微框架,封装比较优雅,API友好,源码注释比较明确,已经发布了1.0版本;具有快速灵活、容错方便等特点,其实对于golang而言,web框架的依赖远比Python、Java更小。

目前在很多使用golang的中小型公司中进行业务开发,使用Gin框架的很多,大家如果想使用golang进行熟练Web开发,可以多关注一下这个框架。

第三个:Iris框架

Iris框架在其官方网站上被描述为GO开发中最快的Web框架,并给出了多框架和多语言之前的性能对比。目前在github上,Iris框架已经收获了14433个star和1493个fork,可见是非常受欢迎的。

在实际开发中,Iris框架与Gin框架的学习曲线几乎相同,所以掌握了Gin就可以轻松掌握Iris框架。

第四个:Echo框架

也是golang的微型Web框架,其具备快速HTTP路由器、支持扩展中间件,同时还支持静态文件服务、Websocket以及支持制定绑定函数,制定相应渲染函数,并允许使用任意的HTML模版引擎。

知识分享之Golang——精选的组件库、组件列表,各种golang组件都可找到

知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录,将其整理出来以文章的形式分享给大家,来进行共同学习。欢迎大家进行持续关注。

知识分享系列目前包含Java、Golang、Linux、Docker等等。

awesome-go 这个组件包含了各种golang中常用的组件,说白了就是一个精选的 Go 框架、库和软件的汇总表。

我们日常需要寻找各种golang组件时在这个列表中基本都可以快速找到。