本文目錄一覽:
- 1、go依賴注入dig包使用-來自uber公司
- 2、GoLang — Gin框架
- 3、golang反射框架Fx
- 4、golang 有哪些比較穩定的 web 開發框架
- 5、知識分享之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組件時在這個列表中基本都可以快速找到。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/193082.html