This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

概念

框架基础概念中英文对照

中文英文描述
结构StructGo 语言的 struct 类型结构体
对象ObjectGo 语言中的实例化对象
接口InterfaceGo 语言中的 interface 类型接口
方法MethodGo 语言中的接口、对象大写字母开头的函数方法
依赖注入Dependency Injection(DI)
自动装载Auto Wire
结构描述符Struct Descriptor (SD)
结构描述键Struct Descriptor Identification(SDID)自动装载模型内索引结构的唯一ID。

1 - 依赖注入

概念

依赖注入(Dependency Injection)是指开发人员无需显式地创建对象,而是通过标签的方式声明字段,由框架负责将实例化对象写入该字段。

优点

依赖注入可以降低代码的耦合度,减少冗余代码量,优化代码逻辑。帮助开发人员面向对象编程,面向接口编程。

IOC-golang 的依赖注入能力

本框架从两个角度实现依赖注入:

  • 结构如何被提供

    开发人员需要准备好需要被注入的结构,将它注册到框架。注册到框架的代码可以由开发人员手动编写,开发人员也可以通过使用注解标记结构,使用 iocli 的代码生成能力自动生成注册代码,从而减少工作量。

    一个带有注解的结构

    // +ioc:autowire=true
    // +ioc:autowire:type=singleton
    
    type App struct {}
    

    由 iocli 工具生成,或用户手动编写的注册代码。

    func init() {
    	singleton.RegisterStructDescriptor(&autowire.StructDescriptor{
    		Interface: &App{},
    		Factory: func() interface{} {
    			return &App{}
    		},
    	})
    }
    
  • 结构如何被使用

    • 通过标签注入

      开发人员需要通过标签来标记需要注入的结构字段。

      需要通过标签注入依赖的结构,其本身必须也注册在框架上。

      // +ioc:autowire=true
      // +ioc:autowire:type=singleton
      
      type App struct {
      	MySubService Service `singleton:"main.ServiceImpl1"` 
      }
      
    • 通过 API 可获取对象,入参为 结构描述 ID 和构造参数(如需要)。

      appInterface, err := singleton.GetImpl("main.App")
      if err != nil {
        panic(err)
      }
      app := appInterface.(*App)
      
      redisInterface, err := normal.GetImpl("github.com/alibaba/ioc-golang/extension/normal/redis.Impl", &Config{
          Address: "localhost:6379"
      })
      if err != nil {
        panic(err)
      }
      redisClient := redisInterface.(*Impl)
      

2 - 自动装载模型

概念

自动装载(Autowire)模型封装了一类对象的装载方式,是本框架对装载过程抽象出的概念和接口。

用户需要定义的结构千变万化,如果每个结构描述符都要提供完整的装载过程信息,将是一件很麻烦的事情。我们可以将一类相似的结构抽象出一个自动装载模型,选择注册在该模型的所有对象都需要遵循该模型的加载策略,这大大降低了用户提供的结构描述符数据量,提高开发效率。

框架内置了两个基础自动装载模型:单例模型(singleton),多例模型(normal)

框架提供了两个扩展的自动装载模型:配置(config),gRPC 客户端(grpc)。其中配置模型是多例模型的扩展,gRPC 客户端是单例模型的扩展。框架内置了基于“配置自动装载模型”的多个结构。例如,用户可以用几行代码将 “gRPC 客户端存根”注册在 “grpc 装载模型” 之上【示例】,方便地从配置文件中的指定位置读入下游主机名、从标签读入客户端名称,注入客户端单例指针。

3 - 结构描述符

概念

结构描述符(Struct Descriptor, SD)用于描述一个被开发者定义的结构,包含对象生命周期的全部信息,例如结构类型是什么,实现了哪些接口,如何被构造等等。

SD可以通过注解的方式使用工具自动生成。但还是推荐开发人员了解本框架定义的结构生命周期和结构描述信息,以便更清晰地开发应用。

对象生命周期

开发人员在 Go 语言开发过程中需要时时关注对象的生命周期,一个常见的对象生命周期如下:

  1. 对象定义:开发人员编码,编写结构,实现接口,确定模型(单例、多例..) 。
  2. 加载全部依赖:依赖的下游对象创建、配置读入等。
  3. 对象创建:产生一个基于该对象的指针
  4. 对象构造:获取全部依赖,并将其组装到空对象中,产生可用对象。
  5. 对象使用:调用对象的方法,读写对象字段。
  6. 对象销毁:销毁对象,销毁无需再使用的依赖对象。

参数

本框架的“参数”概念,是一个结构体,该结构体包含了创建一个对象所需全部依赖,并提供了构造方法。

例如

type Config struct {
	Host      string
	Port      string
	Username  string
	Password  string
}

func (c *Config) New(mysqlImpl *Impl) (*Impl, error) {
	var err error
	mysqlImpl.db, err = gorm.Open(mysql.Open(getMysqlLinkStr(c)), &gorm.Config{})
	mysqlImpl.tableName = c.TableName
	return mysqlImpl, err
}

Config 结构即为 Impl 结构的“参数”。其包含了产生 Impl 结构的全部信息。

结构描述符 (Struct Descriptor)

本框架定义的结构描述符如下:

type StructDescriptor struct {
	Factory       func() interface{} 
	ParamFactory  func() interface{}
	ParamLoader   ParamLoader
	ConstructFunc func(impl interface{}, param interface{}) (interface{}, error)
	DestroyFunc   func(impl interface{})

	autowireType    string
}
  • Factory【必要】

    结构的工厂函数,返回值是未经初始化的空结构指针,例如

    func () interface{}{
    	return &App{}
    }
    
  • ParamFactory【非必要】

    参数的工厂函数,返回值是未经初始化的空参数指针,例如

    func () interface{}{
    	return &Config{}
    }
    
  • ParamLoader【非必要】

    参数加载器定义了参数的各个字段如何被加载,是从注入标签传入、还是从配置读入、或是以一些定制化的方式。

    框架提供了默认的参数加载器,详情参阅 参数加载器概念

  • Constructor【非必要】

    构造函数定义了对象被组装的过程。

    入参为对象指针和参数指针,其中对象指针的所有依赖标签都已被注入下游对象,可以在构造函数中调用下游对象。参数指针的所有字段都已经按照参数加载器的要求加载好。构造函数只负责拼装。

    返回值为经过拼装后的指针。例如:

    func(i interface{}, p interface{}) (interface{}, error) {
      param := p.(*Config)
      impl := i.(*Impl)
      return param.New(impl)
    },
    
  • DestroyFunc 【非必要】

    定义了对象的销毁过程,入参为对象指针。

  • autowireType 【必要】

    定义了对象的自动装载模型,例如单例模型、多例模型等,详情参阅 自动装载模型概念

结构描述ID

  • 定义

结构描述ID定义为:"$(包名).$(结构名)"

结构描述 ID (Struct Description Identification) 在本文档和项目中多处被缩写为 SDID。

SDID 是唯一的,用于索引结构的键,类型为字符串。

  • 使用

开发人员在使用 API 的方式从自动装载模型获取对象时,需要传入SDID来获取。

4 - 参数加载器

概念

参数加载器描述了依赖参数如何在对象构造之前被加载,包括但不限于从配置加载、从标签参数加载等等。

参数加载器作为 SD(结构描述符)的一部分,可以被结构提供方定制化,也可以使用自动装载模型提供的默认参数加载器。

默认参数加载器

任何 SD 内定义参数加载器均被优先执行,如果加载失败,则尝试使用默认参数加载器加载。

默认参数加载器被两个基础自动装载模型(singleton、normal)引入。依此采用三种方式加载参数,如果三种方式均加载失败,则抛出错误。

  • 方式1 从标签指向的对象名加载参数,参考 配置文件结构规范

    Load support load struct described like:
    ```go
    normal.RegisterStructDescriptor(&autowire.StructDescriptor{
    		Factory:   func() interface{}{
    			return &Impl{}
    		},
    		ParamFactory: func() interface{}{
    			return &Config{}
    		},
    		ConstructFunc: func(i interface{}, p interface{}) (interface{}, error) {
    			return i, nil
    		},
    	})
    }
    
    type Config struct {
    	Address  string
    	Password string
    	DB       string
    }
    
    ```
    with
    Autowire type 'normal'
    StructName 'Impl'
    Field:
    	MyRedis Redis `normal:"github.com/alibaba/ioc-golang/extension/normal/redis.Impl, redis-1"`
    
    from:
    
    ```yaml
    extension:
      normal:
        github.com/alibaba/ioc-golang/extension/normal/redis.Impl:
            redis-1:
              param:
                address: 127.0.0.1
                password: xxx
                db: 0
    
  • 方式2 从标签加载参数

    Load support load param like:
    ```go
    type Config struct {
    	Address  string
    	Password string
    	DB       string
    }
    ```
    
    from field:
    
    ```go
    NormalRedis  normalRedis.Redis  `normal:"github.com/alibaba/ioc-golang/extension/normal/redis.Impl,address=127.0.0.1&password=xxx&db=0"`
    ```
    
  • 方式3 从配置加载参数,参考 配置文件结构规范

    Load support load struct described like:
    ```go
    normal.RegisterStructDescriptor(&autowire.StructDescriptor{
    		Factory:   func() interface{}{
    			return &Impl{}
    		},
    		ParamFactory: func() interface{}{
    			return &Config{}
    		},
    		ConstructFunc: func(i interface{}, p interface{}) (interface{}, error) {
    			return i, nil
    		},
    	})
    }
    
    type Config struct {
    	Address  string
    	Password string
    	DB       string
    }
    ```
    with
    Autowire type 'normal'
    StructName 'Impl'
    
    from:
    
    ```yaml
    autowire:
      normal:
          github.com/alibaba/ioc-golang/extension/normal/redis.Impl:
            param:
              address: 127.0.0.1
              password: xxx
              db: 0
    

5 - 注解

概念

注解(annotation) 是 Go 代码中符合特定格式的注释,一般位于结构定义之前。可被命令行工具扫描,从而获取结构信息,自动生成需要的代码。 例如快速开始示例中的

// +ioc:autowire=true
// +ioc:autowire:type=singleton

type App struct {
	...
}

注解在 Go 应用开发的过程中,是一种直观、清晰的结构描述方式,通过使用注解进行标注,使用工具自动生成相关代码,可减少开发人员的工作量,降低代码重复率。

注解与代码生成

注解与代码生成能力,是为了让开发者无需关心SD(结构描述符)的组装和注册。开发者只需定义好结构,正确标注注解,即可使用 iocli 工具自动生成当前目录和子目录下的 SD 。

iocli 工具支持的注解

详情参阅 iocli #结构注解