欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析golang的依賴注入

 更新時(shí)間:2022年09月28日 09:15:49   作者:bobo_simpler  
這篇文章主要介紹了淺析golang的依賴注入,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

前言

如果是做web開發(fā),對依賴注入肯定不陌生,java程序員早就習(xí)慣了spring提供的依賴注入,做業(yè)務(wù)開發(fā)時(shí)非常方便,只關(guān)注業(yè)務(wù)邏輯即可,對象之間的依賴關(guān)系都交給框架。

golang是強(qiáng)類型語言,編譯后是機(jī)器碼,所以一般使用 反射 或 代碼生成 解決依賴注入的問題

基于反射的DI

基于反射解決DI問題的框架, 使用比較多的是Uber的 dig 庫

官方的例子:

type Config struct {
        Prefix string
}

//初始化Config函數(shù)
func NewConfig()(*Config, error) {
        // In a real program, the configuration will probably be read from a
        // file.
        var cfg Config
        err := json.Unmarshal([]byte(`{"prefix": "[foo] "}`), &cfg)
        return &cfg, err
}

//初始化logger函數(shù)
func NewLogger(cfg *Config) *log.Logger {
    return log.New(os.Stdout, cfg.Prefix, 0)
}

func Handle() (l *log.Logger) {
    l.Print("You've been invoked")
}

func main() {
    //初始化dig對象
    c := dig.New()

    //Provide方法用來設(shè)置依賴的對象
    er := c.Provide(NewConfig)
    if err != nil {
        panic(err)
    }

    //設(shè)置依賴的對象
    err = c.Provide(NewLogger)
    if err != nil {
        panic(err)
    }
    
    //執(zhí)行Handle()方法
    //Handle依賴 Config 和 Logger,使用Invoke執(zhí)行方法時(shí)會自動注入依賴(依賴的對象要傳入Provide方法中)
    err = c.Invoke(Handle)
    if err != nil {
        panic(err)
    }
    // Output:
    // [foo] You've been invoked
}

dig提供了一個(gè)容器(container),所有的依賴項(xiàng)通過Provide方法添加,執(zhí)行某個(gè)方法時(shí)使用Invoke方法,該方法會自動注入所需要的依賴。

dig使用反射機(jī)制解決DI問題,所以代碼執(zhí)行性能上會有損耗

并且因?yàn)槭褂梅瓷渌钥赡艹霈F(xiàn)編譯時(shí)沒有錯(cuò)誤,執(zhí)行時(shí)報(bào)空指針

詳情使用方法可以參考官方文檔,dig可以繼承到gin框架中,有興趣的可以看看資料。

筆者不太喜歡這種使用方式,為了依賴注入破壞了代碼原有的調(diào)用方式。

基于代碼生成的DI

wire庫是google出的解決golang DI問題的工具,它可以 自動生成依賴注入的代碼,節(jié)省了手動去處理依賴關(guān)系

github地址

wire對原有代碼的侵入度很低,開發(fā)過程中,在依賴注入代碼處調(diào)用Build方法(例子中是初始化controller對象)就可以了

// +build wireinject

package main

import (
    "encoding/json"
    "fmt"
    "github.com/google/wire"
    "net/http"
)

type DataSource struct {
    Operation string
}

func NewDataSource() DataSource {
    return DataSource{Operation: "operation_name"}
}

//==================

type Dao struct {
    DataSource DataSource
}

func NewDao(ds DataSource) *Dao {
    return &Dao{
        DataSource: ds,
    }
}

func (d *Dao) GetItemList() ([]string, error) {
    //TODO 拿到DB對象做查詢操作
    fmt.Printf("db object: %s", d.DataSource.Operation)
    return []string{d.DataSource.Operation, "item1", "item2"}, nil
}

//====================

type Service struct {
    Dao *Dao
}

func NewService(dao *Dao) *Service {
    return &Service{Dao: dao}
}

func (s *Service) GetItemList() ([]string, error) {
    return s.Dao.GetItemList()
}

//=====================

type Controller struct {
    Service *Service
}

func NewController(service *Service) *Controller {
    return &Controller{Service: service}
}

func (c *Controller) GetItemList() ([]string, error) {
    return c.Service.GetItemList()
}

var MegaSet = wire.NewSet(NewDataSource, NewDao, NewService, NewController)

func initializeController() *Controller {
    wire.Build(MegaSet)
    return &Controller{}
}

func getItemList(w http.ResponseWriter, r *http.Request) {
    controller := initializeController()
    itemList, _ := controller.GetItemList()
    output, _ := json.Marshal(itemList)
    fmt.Fprintf(w, string(output))
}

func main() {
    http.HandleFunc("/items", getItemList)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        panic(err)
    }
}

然后再項(xiàng)目根目錄執(zhí)行wire命令,會生成構(gòu)建好依賴關(guān)系的代碼(以_gen結(jié)尾的文件)

// Code generated by Wire. DO NOT EDIT.

//go:generate go run github.com/google/wire/cmd/wire
//+build !wireinject

package main

import (
    "encoding/json"
    "fmt"
    "github.com/google/wire"
    "net/http"
)

// Injectors from main.go:
// 此處是生成的代碼
func initializeController() *Controller {
    dataSource := NewDataSource()
    dao := NewDao(dataSource)
    service := NewService(dao)
    controller := NewController(service)
    return controller
}

// main.go:

type DataSource struct {
    Operation string
}

func NewDataSource() DataSource {
    return DataSource{Operation: "operation_name"}
}

type Dao struct {
    DataSource DataSource
}

func NewDao(ds DataSource) *Dao {
    return &Dao{
        DataSource: ds,
    }
}

func (d *Dao) GetItemList() ([]string, error) {
    fmt.Printf("db object: %s", d.DataSource.Operation)
    return []string{d.DataSource.Operation, "item1", "item2"}, nil
}

type Service struct {
    Dao *Dao
}

func NewService(dao *Dao) *Service {
    return &Service{Dao: dao}
}

func (s *Service) GetItemList() ([]string, error) {
    return s.Dao.GetItemList()
}

type Controller struct {
    Service *Service
}

func NewController(service *Service) *Controller {
    return &Controller{Service: service}
}

func (c *Controller) GetItemList() ([]string, error) {
    return c.Service.GetItemList()
}

var MegaSet = wire.NewSet(NewDataSource, NewDao, NewService, NewController)

func getItemList(w http.ResponseWriter, r *http.Request) {
    controller := initializeController()
    itemList, _ := controller.GetItemList()
    output, _ := json.Marshal(itemList)
    fmt.Fprintf(w, string(output))
}

func main() {
    http.HandleFunc("/items", getItemList)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        panic(err)
    }
}

關(guān)鍵代碼:

//執(zhí)行wire命令前的代碼
func initializeController() *Controller {
    wire.Build(MegaSet)
    return &Controller{}
}

//執(zhí)行后生成的代碼
// Injectors from main.go:
func initializeController() *Controller {
    dataSource := NewDataSource()
    dao := NewDao(dataSource)
    service := NewService(dao)
    controller := NewController(service)
    return controller
}

通過生成代碼解決依賴注入的問題,既能提升開發(fā)效率,又不影響代碼性能,wire更高級的用法可以去github document查看

  • tips: 如果報(bào)錯(cuò)誤 other declaration of xxxx ,請?jiān)谠次募^加上 //+build wireinject
  • go-zero框架也是用wire解決DI問題

到此這篇關(guān)于淺析golang的依賴注入的文章就介紹到這了,更多相關(guān)go依賴注入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Golang利用反射reflect動態(tài)調(diào)用方法

    詳解Golang利用反射reflect動態(tài)調(diào)用方法

    這篇文章主要介紹了詳解Golang利用反射reflect動態(tài)調(diào)用方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Golang中g(shù)oroutine和channel使用介紹深入分析

    Golang中g(shù)oroutine和channel使用介紹深入分析

    一次只做一件事情并不是完成任務(wù)最快的方法,一些大的任務(wù)可以拆解成若干個(gè)小任務(wù),goroutine可以讓程序同時(shí)處理幾個(gè)不同的任務(wù),goroutine使用channel來協(xié)調(diào)它們的工作,channel允許goroutine互相發(fā)送數(shù)據(jù)并同步,這樣一個(gè)goroutine就不會領(lǐng)先于另一個(gè)goroutine
    2023-01-01
  • 深入淺出go依賴注入工具Wire的使用

    深入淺出go依賴注入工具Wire的使用

    但隨著項(xiàng)目規(guī)模的增長,組件之間的依賴關(guān)系變得復(fù)雜,手動管理可能會很繁瑣,所以本文將深入探討一個(gè)備受歡迎的?Go?語言依賴注入工具——?Wire,感興趣的可以了解下
    2023-09-09
  • Golang中Map按照Value大小排序的方法實(shí)例

    Golang中Map按照Value大小排序的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于Golang中Map按照Value大小排序的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-03-03
  • 詳解如何在golang項(xiàng)目開發(fā)中創(chuàng)建自己的Module

    詳解如何在golang項(xiàng)目開發(fā)中創(chuàng)建自己的Module

    既然我們使用了很多開源的 module為我們的日常開發(fā)提供了很多的便捷性,那我們該如何實(shí)現(xiàn)自己的 module 來提供給團(tuán)隊(duì)中使用,接下小編就給大家介紹一下在golang項(xiàng)目開發(fā)如何創(chuàng)建自己的Module,需要的朋友可以參考下
    2023-09-09
  • Golang實(shí)現(xiàn)自定義recovery中間件

    Golang實(shí)現(xiàn)自定義recovery中間件

    在?Golang?的?Web?項(xiàng)目中,自定義?recovery?中間件是一種常見的做法,用于捕獲并處理應(yīng)用程序的運(yùn)行時(shí)錯(cuò)誤,下面我們就來看看具體如何實(shí)現(xiàn)吧
    2023-09-09
  • Go語言單元測試超詳細(xì)解析

    Go語言單元測試超詳細(xì)解析

    本文介紹了了Go語言單元測試超詳細(xì)解析,測試函數(shù)分為函數(shù)的基本測試、函數(shù)的組測試、函數(shù)的子測試,進(jìn)行基準(zhǔn)測試時(shí)往往是對函數(shù)的算法進(jìn)行測驗(yàn),有時(shí)后一個(gè)算法在測試數(shù)據(jù)的基量不同時(shí)測試出的效果會不同我們需要對不同數(shù)量級的樣本進(jìn)行測試,下文需要的朋友可以參考下
    2022-02-02
  • Go錯(cuò)誤處理的幾種方式

    Go錯(cuò)誤處理的幾種方式

    在Go語言中,錯(cuò)誤處理是一種重要的編程模式,它用于處理可能出現(xiàn)的錯(cuò)誤或異常情況,本文就來介紹一下Go錯(cuò)誤處理的幾種方式,感興趣的可以了解一下
    2023-11-11
  • Go安裝和環(huán)境配置圖文教程

    Go安裝和環(huán)境配置圖文教程

    本文主要介紹了Go安裝和環(huán)境配置圖文教程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Air實(shí)現(xiàn)Go程序?qū)崟r(shí)熱重載使用過程解析示例

    Air實(shí)現(xiàn)Go程序?qū)崟r(shí)熱重載使用過程解析示例

    這篇文章主要為大家介紹了Air實(shí)現(xiàn)Go程序?qū)崟r(shí)熱重載使用過程解析示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04

最新評論