網站首頁 編程語言 正文
前言
如果是做web開發,對依賴注入肯定不陌生,java程序員早就習慣了spring提供的依賴注入,做業務開發時非常方便,只關注業務邏輯即可,對象之間的依賴關系都交給框架。
golang是強類型語言,編譯后是機器碼,所以一般使用?反射?或?代碼生成?解決依賴注入的問題
基于反射的DI
基于反射解決DI問題的框架, 使用比較多的是Uber的?dig?庫
官方的例子:
type Config struct { Prefix string } //初始化Config函數 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函數 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方法用來設置依賴的對象 er := c.Provide(NewConfig) if err != nil { panic(err) } //設置依賴的對象 err = c.Provide(NewLogger) if err != nil { panic(err) } //執行Handle()方法 //Handle依賴 Config 和 Logger,使用Invoke執行方法時會自動注入依賴(依賴的對象要傳入Provide方法中) err = c.Invoke(Handle) if err != nil { panic(err) } // Output: // [foo] You've been invoked }
dig提供了一個容器(container),所有的依賴項通過Provide方法添加,執行某個方法時使用Invoke方法,該方法會自動注入所需要的依賴。
dig使用反射機制解決DI問題,所以代碼執行性能上會有損耗
并且因為使用反射所以可能出現編譯時沒有錯誤,執行時報空指針
詳情使用方法可以參考官方文檔,dig可以繼承到gin框架中,有興趣的可以看看資料。
筆者不太喜歡這種使用方式,為了依賴注入破壞了代碼原有的調用方式。
基于代碼生成的DI
wire庫是google出的解決golang DI問題的工具,它可以 自動生成依賴注入的代碼,節省了手動去處理依賴關系
github地址
wire對原有代碼的侵入度很低,開發過程中,在依賴注入代碼處調用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) } }
然后再項目根目錄執行wire命令,會生成構建好依賴關系的代碼(以_gen結尾的文件)
// 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) } }
關鍵代碼:
//執行wire命令前的代碼 func initializeController() *Controller { wire.Build(MegaSet) return &Controller{} } //執行后生成的代碼 // Injectors from main.go: func initializeController() *Controller { dataSource := NewDataSource() dao := NewDao(dataSource) service := NewService(dao) controller := NewController(service) return controller }
通過生成代碼解決依賴注入的問題,既能提升開發效率,又不影響代碼性能,wire更高級的用法可以去github document查看
- tips: 如果報錯誤?
other declaration of xxxx
?,請在源文件頭加上?//+build wireinject
- go-zero框架也是用wire解決DI問題
原文鏈接:https://blog.csdn.net/bobo_simpler/article/details/125363060
相關推薦
- 2022-07-03 el-form表單新增表單項動態校驗;el-form校驗動態表單v-if不生效;
- 2022-05-23 ZooKeeper分布式協調服務設計核心概念及安裝配置_zabbix
- 2023-03-19 匯編語言LDR指令和LDR偽指令詳解_匯編語言
- 2023-01-29 python缺失值填充方法示例代碼_python
- 2022-09-16 Go語言實現UDP協議及TCP通訊_Golang
- 2022-05-12 Kotlin 擴展函數 之 可空
- 2022-04-01 k8s Error: could not find tiller
- 2022-05-03 基于Python制作一款屏幕顏色提取器_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支