当前位置: 首页 > 工具软件 > Go-IOC > 使用案例 >

长安链源码学习v2.2.1--ioc机制(十)

穆正青
2023-12-01

前面共同学习长安链ioc如何使用,下面聊聊IOC的实现原理。本节主要分析两个方法,RegisterResolve

1.func (c *Container) Register(constructor interface{}, options ...Option) error

第一个参数:constructor ,某实现的构造方法,例如:NewFileStore
第二个参数:Option,例如:InterfaceParametersDefault等,上节有介绍。

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参数,包括执行InterfaceParametersDefault等方法。

       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方法把实现的构造方法、类型、参数记录到containerbind字段。
Resolve方法根据方法类型寻找匹配的bind字段,与abstraction 指针进行绑定。

1)设置Resolve参数,包括执行ArgumentsResolveName等方法。

       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还提供其他方法调用,逻辑比较清晰,大家可自行分析。

 类似资料: