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


    前面共同学习长安链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")
    	}
    
    • 1
    • 2
    • 3
    • 4

    2)创建一个binding对象,用于设置构造方法 + 默认参数值

        b := &binding{constructor: constructor, specifiedParameters: make(map[int]interface{})}
    
    • 1

    3)设置Register参数,包括执行InterfaceParametersDefault等方法。

           for _, op := range options {
    			err := op(b)
    			if err != nil {
    				return err
    			}
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    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]
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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)
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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
    			}
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2)abstraction 必须是指针

    if receiverType.Kind() == reflect.Ptr {
    
    • 1

    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())
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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
    		}()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    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))
    
    • 1
    • 2
    • 3
    • 4
    • 5

    长安链ioc还提供其他方法调用,逻辑比较清晰,大家可自行分析。

  • 相关阅读:
    Linux高并发服务器开发第六章:项目执行流程讲解
    什么是分布式锁?几种分布式锁分别是怎么实现的?
    关于webpack(v5.74.0)的dllPlugin插件的原理
    DHorse系列文章之镜像制作
    我的Quick Latex For Obsidian-Setting(持续更新)
    如何做系统架构设计
    手机+卫星的科技狂想
    云原生之使用Docker部署slash书签共享平台
    Android查看公钥与MD5
    【NSArray和NSDictionary的内存管理 Objective-C语言】
  • 原文地址:https://blog.csdn.net/xjmtxwd24/article/details/126620349