參考:
https://studygolang.com/articles/13783?fr=sidebar
https://studygolang.com/articles/7716
先寫著,我現在吃不透原理
一、IOC
Ioc的思想就是解耦,只依賴容器而不依賴具體的類,當你的類有修改時,最多需要改動一下容器相關代碼,業務代碼並不受影響。
golang的依賴注入原理
步驟如下:(golang不支援動態建立對象,所以需要先手動建立對象然後注入,java可以直接動態建立對象)
1.通過反射讀取對象的依賴(golang是通過tag實現)
2.在容器中尋找有無該對象執行個體
3.如果有該對象執行個體或者建立對象的Factory 方法,則注入對象或使用工廠建立對象並注入
4.如果無該對象執行個體,則報錯
代碼實現
package diimport ( "sync" "reflect" "fmt" "strings" "errors")var ( ErrFactoryNotFound = errors.New("factory not found"))type factory = func() (interface{}, error)// 容器type Container struct { sync.Mutex singletons map[string]interface{} factories map[string]factory}// 容器執行個體化func NewContainer() *Container { return &Container{ singletons: make(map[string]interface{}), factories: make(map[string]factory), }}// 註冊單例對象func (p *Container) SetSingleton(name string, singleton interface{}) { p.Lock() p.singletons[name] = singleton p.Unlock()}// 擷取單例對象func (p *Container) GetSingleton(name string) interface{} { return p.singletons[name]}// 擷取執行個體對象func (p *Container) GetPrototype(name string) (interface{}, error) { factory, ok := p.factories[name] if !ok { return nil, ErrFactoryNotFound } return factory()}// 設定執行個體對象工廠func (p *Container) SetPrototype(name string, factory factory) { p.Lock() p.factories[name] = factory p.Unlock()}// 注入依賴func (p *Container) Ensure(instance interface{}) error { elemType := reflect.TypeOf(instance).Elem() ele := reflect.ValueOf(instance).Elem() for i := 0; i < elemType.NumField(); i++ { // 遍曆欄位 fieldType := elemType.Field(i) tag := fieldType.Tag.Get("di") // 擷取tag diName := p.injectName(tag) if diName == "" { continue } var ( diInstance interface{} err error ) if p.isSingleton(tag) { diInstance = p.GetSingleton(diName) } if p.isPrototype(tag) { diInstance, err = p.GetPrototype(diName) } if err != nil { return err } if diInstance == nil { return errors.New(diName + " dependency not found") } ele.Field(i).Set(reflect.ValueOf(diInstance)) } return nil}// 擷取需要注入的依賴名稱func (p *Container) injectName(tag string) string { tags := strings.Split(tag, ",") if len(tags) == 0 { return "" } return tags[0]}// 檢測是否單例依賴func (p *Container) isSingleton(tag string) bool { tags := strings.Split(tag, ",") for _, name := range tags { if name == "prototype" { return false } } return true}// 檢測是否執行個體依賴func (p *Container) isPrototype(tag string) bool { tags := strings.Split(tag, ",") for _, name := range tags { if name == "prototype" { return true } } return false}// 列印容器內部執行個體func (p *Container) String() string { lines := make([]string, 0, len(p.singletons)+len(p.factories)+2) lines = append(lines, "singletons:") for name, item := range p.singletons { line := fmt.Sprintf(" %s: %x %s", name, &item, reflect.TypeOf(item).String()) lines = append(lines, line) } lines = append(lines, "factories:") for name, item := range p.factories { line := fmt.Sprintf(" %s: %x %s", name, &item, reflect.TypeOf(item).String()) lines = append(lines, line) } return strings.Join(lines, "\n")}