前面共同学习长安链ioc如何使用,下面聊聊IOC的实现原理。本节主要分析两个方法,
Register
、Resolve
。
1.func (c *Container) Register(constructor interface{}, options ...Option) error
第一个参数:constructor
,某实现的构造方法,例如:NewFileStore
第二个参数:Option
,例如:Interface
、Parameters
、Default
等,上节有介绍。
1) constructor
参数必须是函数
reflectedResolver := reflect.TypeOf(constructor)
if reflectedResolver.Kind() != reflect.Func {
return errors.New("container: the constructor must be a function")
}
2)创建一个binding
对象,用于设置构造方法 + 默认参数值
b := &binding{constructor: constructor, specifiedParameters: make(map[int]interface{})}
3)设置Register
参数,包括执行Interface
、Parameters
、Default
等方法。
for _, op := range options {
err := op(b)
if err != nil {
return err
}
}
4)读取构造方法返回值类型,如果Register
设置过container.Interface()
,则container.Interface()
的值(b.resolveTypes[i]
)作为构造方法的类型。
resolveType := reflectedResolver.Out(i)
if len(b.resolveTypes) > i && b.resolveTypes[i] != nil { //如果指定了映射的interface,则使用指定的
if !resolveType.Implements(b.resolveTypes[i]) {
return errors.New("resolve type " + resolveType.String() + " not implement " + b.resolveTypes[i].String())
}
resolveType = b.resolveTypes[i]
}
5)以构造方法返回值类型为key,以binding方法为体将该结构存储到container下。如果该key存在过,则叠加存储;如果该key不存在,则创建。
if namedBinding, has := c.bind[resolveType]; has { //增加新binding
namedBinding.addNewBinding(b, b.isDefault)
} else { //没有注册过这个接口的任何绑定
c.bind[resolveType] = newNamedBinding(b)
}
2.func (c *Container) Resolve(abstraction interface{}, options ...ResolveOption) error
前面Register
方法把实现的构造方法、类型、参数记录到container
的bind
字段。
Resolve
方法根据方法类型寻找匹配的bind
字段,与abstraction
指针进行绑定。
1)设置Resolve
参数,包括执行Arguments
、ResolveName
等方法。
for _, op := range options {
err := op(b)
if err != nil {
return err
}
}
2)abstraction
必须是指针
if receiverType.Kind() == reflect.Ptr {
3)从bind结构中找到匹配的接口类型
elem := receiverType.Elem()
b, err := c.getBinding(elem, option.name)
if err != nil {
return errors.New("resolve type: " + receiverType.String() + " no concrete found for: " + elem.String())
}
4)根据Arguments
获取构造方法的参数,替换Register传入的Parameters
参数
args := b.specifiedParameters
if len(option.args) > 0 {
for i, v := range option.args {
args[i] = v
}
}
oldArgs := b.specifiedParameters
b.specifiedParameters = args
defer func() {
b.specifiedParameters = oldArgs
}()
5)找到构造方法、也知道参数,调用该方法绑定实现对象
instance, err := b.resolve(c)
if err != nil {
return err //errors.New("resolve type: " + receiverType.String() + " " + err.Error())
}
reflect.ValueOf(abstraction).Elem().Set(reflect.ValueOf(instance))
长安链ioc还提供其他方法调用,逻辑比较清晰,大家可自行分析。