依賴
總結下先有的獲取物件依賴方式
- 比較原始的New, 全域性global儲存
- 基於反射讀取物件的依賴, 程式啟動時由DI庫例項化(代表作
dig
等) - 基於反射讀取物件的依賴, 編譯前生成完整構建函式(代表作
wire
等)
第一種:最方便, 直接快捷, 大量依賴時候, 但是因為是手動的, 容易出現例項順序非預期, 不方便自動測試, mock等。
第二種:因為是啟動時反射獲取依賴的, 需要定義額外的函式給DI系統解析, 例如一個結構的注入必須要要額外的程式碼, 非常麻煩, 不建議使用
// 提供者
err := c.Provide(func(conn *sql.DB) (*UserGateway, *CommentGateway, error) {
// ...
})
if err != nil {
// ...
}
// 使用者
err := c.Invoke(func(l *log.Logger) {
// ...
})
if err != nil {
// ...
}
第三種, 同樣是基於反射, 所以依然需要一個額外函式(只有配置資訊)提供反射資訊, 生成同名函式, 便捷度基本和手動New一致, wire
由 Google 開源
func InitializeNewGormProvider() *Gorm {
wire.Build(NewGormProvider, InitializeNewConfProvider)
return nil
}
我的方案
原理和wire一樣, 根據配置資訊生成自動構建函式, 但是不基於反射, 因為反射需要程式是完整的, 編譯後才讀取資訊, 相對慢, 需要每個目錄改完手動執行wire .
命令(每個目錄每次花費1秒等)。
先看一個場景, 資料庫服務是依賴配置服務, 從結構體就能看出來, 不需要func InitializeNewGormProvider() *Gorm{}
函式反射, 未了更加準確(防止注入了不需要的內容)新增一個taginject:""
和@Bean
註解
// @Bean
type Gorm struct {
conf *Conf `inject:""`
}
所以,注入其實是可以直接基於原始碼的資訊都能實現的。
我只要實現一個go
程式碼解析工具,就能生成和wire
工具生成相同的程式碼, 因為go原始碼的關鍵字和結構實在是太簡單了, 沒有多少語法糖, 做一下分詞
再按語法規則讀取原始碼資訊, 工具實現比較容易
。
工具使用php實現( 公司都是mac,php環境mac電腦自帶, 方便使用模版生成go程式碼)
github.com/go-home-admin/home-tool...
重要是php解析很快, 整個專案生成一次都是一秒內
ORM 生成程式碼
編寫工具後, 也可以生成其他輔助程式碼, 例如原始結構, 新增@Orm後, 自動根據欄位資訊生成通用程式碼
// @Orm
type Gorm struct {
Id uint32 `json:"id"`
UserName string `json:"user_name"`
}
邏輯就可以直接使用
u := &UsersTable{}
data := u.WhereUserName("test").And(func(table *UsersTable) {
table.WhereId(1).OrWhereId(2)
}).Or(func(table *UsersTable) {
table.WhereId(2).Or(func(table *UsersTable) {
table.WhereId(1)
})
}).Find()
// select * form users where user_name = ? and (id = ? or id = ?) or (id = ? or (id = ?))
utils.Dump(data)
本作品採用《CC 協議》,轉載必須註明作者和本文連結