- 一、控制反转是什么?
- 1、如何理解 Ioc 呢?
- 2、控制反转和依赖注入
- 3、小总结
- 二、依赖注入代码实现
使用过 Java 的一定知道依赖注入这个概念,说到依赖注入就不得不提一下控制反转(IOC),这个两个不是什么复杂的技术,而是一种思想,一种设计模式,接下来我谈下我对这个设计模式的理解,以及如何使用golang实现依赖注入。
一、控制反转是什么?1、如何理解 Ioc 呢?控制反转即Ioc(后续使用 Ioc 来表述控制反转),Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转?什么是正转?反转了是为什么什么?带着疑问往下看。
-
谁控制谁?
在程序中,我们直接申明一个对象,是程序主动去创建依赖的对象;Ioc的思想是专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;Ioc容器控制了对象,控制对象的获取。 -
什么是正转?
说反转之前,先了解下什么是正转,正转顾名思义,程序中由我们自己在对象中主动控制去直接获取依赖对象。 -
什么是反转?
反转即,由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
DI—Dependency Injection,即“依赖注入”(后续使用 DI 来表述依赖注入)
组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。
通过依赖注入机制,我们只需要通过简单的初始化,而无需任何代码就可指定目标依赖对象,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
- 谁依赖谁?
程序依赖 Ioc 容器 - 谁注入谁?
Ioc 容器注入应用程序某个对象,应用程序依赖的对象 - 注入了什么?
注入某个对象所需要的资源
Ioc 和 DI 是同一个概念的不同角度描述,设计理念是一样的。相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。
二、依赖注入代码实现欢迎点赞、使用、提出改进意见:点击跳转 github,下方讲解核心的实现流程。
-
初始化 core.go
type LoadFunc func(ILoader) error var ( ErrNotFound = errors.New("key not found") shared = NewSingleLoader() funcs = make([]LoadFunc, 0, 16) ) func DefaultLoader() ILoader { return shared } type ILoader interface { Register(key interface{}, value interface{}) error // 加载所有注册变量 LoadingAll() // 加载某结构体下变量 Loading(v interface{}) } // 注册 注册方法 func Register(f LoadFunc) { funcs = append(funcs, f) } // 将 core 的 funcs 保存的注册方法 // 全局注入到 loader 的集合中 func LoadingAll(loader ILoader) (err error) { for _, f := range funcs { err = f(loader) if err != nil { return err } } loader.LoadingAll() return } -
初始化 single.go
var _ ILoader = new(singleLoader) // 初始化单例装载器 func NewSingleLoader() ILoader { return &singleLoader{ objs: make(map[interface{}]reflect.Value), } } // 全局 Ioc容器 type singleLoader struct { objs map[interface{}]reflect.Value } func (s *singleLoader) Register(key interface{}, value interface{}) error { _, ok := s.objs[key] if ok { return errors.New(fmt.Sprintf("key duplicate: %v", key)) } s.objs[key] = reflect.ValueOf(value) return nil } func (s *singleLoader) LoadingAll() { for _, v := range s.objs { s.Loading(v) } } // 装载结构体中依赖的字段 func (s *singleLoader) Loading(v interface{}) { var value reflect.Value var ok bool if value, ok = v.(reflect.Value); !ok { value = reflect.ValueOf(v) } loop: for { switch value.Kind() { case reflect.Ptr: value = value.Elem() case reflect.Interface: value = value.Elem() default: break loop } } if value.Kind() != reflect.Struct { return } for i := 0; i < value.NumField(); i++ { name := value.Type().Field(i).Tag.Get(LoaderTag) temp, ok := s.objs[name] if ok { field := value.Field(i) if field.CanSet() { field.Set(temp) } else { field = reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem() field.Set(temp) } } }



