Golang轻量级IoC容器安装使用示例

目录
  • 1. iocgo简介
  • 2. iocgo如何使用
    • 2.1 iocgo包的安装
    • 2.2 使用示例与说明
      • 2.2.1 最简单的例子:
      • 2.22. Register 的选项
      • 2.2.3. 注册实例
      • 2.2.4. 获得实例
      • 2.2.5. 结构体参数和字段填充
      • 2.2.6. 函数调用
    • 2.3 参考:
  • 3. 总结

1. iocgo简介

习惯于Java或者C#开发的人应该对控制反转与依赖注入应该再熟悉不过了。在Java平台有鼎鼎大名的Spring框架,在C#平台有Autofac,Unity,Windsor等,我当年C#开发时用的最多的就是Windsor。使用IoC容器是面向对象开发中非常方便的解耦模块之间的依赖的方法。各个模块之间不依赖于实现,而是依赖于接口,然后在构造函数或者属性或者方法中注入特定的实现,方便了各个模块的拆分以及模块的独立单元测试。

在[长安链]的设计中,各个模块可以灵活组装,模块之间的依赖基于protocol中定义的接口,每个接口有一个或者多个官方实现,当然第三方也可以提供该接口更多的实现。为了实现更灵活的组装各个模块,管理各个模块的依赖关系,于是我写了iocgo这个轻量级的golang版Ioc容器。

2. iocgo如何使用

2.1 iocgo包的安装

现在go官方版本已经出到1.17了,当然我在代码中其实也没有用什么新版本的新特性,于是就用1.15版本或者之后的Go版本即可。要使用iocgo包,直接通过go get添加到项目中:

go get github.com/studyzy/iocgo

2.2 使用示例与说明

2.2.1 最简单的例子:

type Fooer interface {
	Foo(int)
}
type Foo struct {
}
func (Foo)Foo(i int)  {
	fmt.Println("foo:",i)
}
type Barer interface {
	Bar(string)
}
type Bar struct {
}
func (Bar) Bar(s string){
	fmt.Println("bar:",s)
}
type Foobarer interface {
	Say(int,string)
}
type Foobar struct {
	foo Fooer
	bar Barer
}
func NewFoobar(f Fooer,b Barer) Foobarer{
	return &Foobar{
		foo: f,
		bar: b,
	}
}
func (f Foobar)Say(i int ,s string)  {
	f.foo.Foo(i)
	f.bar.Bar(s)
}
func TestContainer_SimpleRegister(t *testing.T) {
	container := NewContainer()
	container.Register(NewFoobar)
	container.Register(func() Fooer { return &Foo{} })
	container.Register(func() Barer { return &Bar{} })
	var fb Foobarer
	container.Resolve(&fb)
	fb.Say(123,"Hello World")
}

这里我使用NewContainer()创建了一个新的容器,然后在容器中调用Register方法注册了3个接口和对应的构造函数,分别是:

  • Foobarer接口对应NewFoobar(f Fooer,b Barer)构造函数
  • Fooer接口对应构造&Foo{}的匿名函数。
  • Barer接口对应构造&Bar{}的匿名函数。

接下来调用Resolve函数,并传入var fb Foobarer 这个接口变量的指针,iocgo就会自动去构建Foobarer对应的实例,并最终将实例赋值到fb这个变量上,于是最后我们就可以正常调用fb.Say实例方法了。

2.22. Register 的选项

iocgo的注册interface到对象的函数定义如下:

func Register(constructor interface{}, options ...Option) error

iocgo为Register函数提供了以下参数选项可根据实际情况选择性使用:

  • Name 为某个interface->对象的映射命名
  • Optional 表名这个构造函数中哪些注入的interface参数是可选的,如果是可选,那么就算找不到interface对应的实例也不会报错。
  • Interface 显式声明这个构造函数返回的实例是映射到哪个interface。
  • Lifestyle(isTransient) 声明这个构造函数在构造实例后是构造的临时实例还是单例实例,如果是临时实例,那么下次再获取该interface对应的实例时需要再次调用构造函数,如果是单例,那么就缓存实例到容器中,下次再想获得interface对应的实例时直接使用缓存中的,不需要再次构造。
  • DependsOn 这个主要是指定构造函数中的某个参数在通过容器获得对应的实例时,应该通过哪个Name去获得对应的实例。
  • Parameters 这个主要用于指定构造函数中的某些非容器托管的参数,比如某构造函数中有int,string等参数,而这些参数的实例是不需要通过ioc容器进行映射托管的,那么就在这里直接指定。
  • Default 这个主要用于设置一个interface对应的默认的实例,也就是如果没有指定Name的情况下,应该找哪个实例。 关于每一个参数该如何使用,我都写了UT样例,具体参考: container_test.go

2.2.3. 注册实例

如果我们已经有了某个对象的实例,那么可以将该实例和其想映射的interface直接注册到ioc容器中,方便其他依赖的对象获取,RegisterInstance函数定义如下:

RegisterInstance(interfacePtr interface{}, instance interface{}, options ...Option) error

使用上也很简单,直接将实例对应的interface的指针作为参数1,实例本身作为参数2,传入RegisterInstance即可:

b := &Bar{}
var bar Barer //interface
container.RegisterInstance(&bar, b) // register interface -> instance

2.2.4. 获得实例

相关映射我们通过Register函数和RegisterInstance函数已经注册到容器中,接下来就需要从容器获得指定的实例了。获得实例需要调用函数:

func Resolve(abstraction interface{}, options ...ResolveOption) error

这里第一个参数abstraction是我们想要获取的某个interface的指针,第二个参数是可选参数,目前提供的选项有:

  • ResolveName 指定使用哪个name的interface和实例的映射,如果不指定,那么就是默认映射。
  • Arguments 指定在调用对应的构造函数获得实例时,传递的参数,比如int,string等类型的不在ioc容器中托管的参数,可以在这里指定。如果构造函数本身需要这些参数,而且在前面Register的时候已经通过Parameters选项进行了指定,那么这里新的指定会覆盖原有Register的指定。
var fb Foobarer
err:=container.Resolve(&fb)

另外如果我们的构造函数return的值中支持error,而且实际构造的时候确实返回了error,那么Resolve函数也会返回对应的这个err。

特别注意:Resolve的第一个参数是申明的某个interface的指针,一定要是指针,不能直接传interface

2.2.5. 结构体参数和字段填充

有些时候构造函数的入参非常多,于是我们可以申明一个结构体,把所有入参都放入这个结构体中,这样构造函数就只需要一个参数了。iocgo也支持自动填充这个结构体中interface对应的实例,从而构造新的对象。另外iocgo也提供了Fill方法,可以直接填充某个结构体,比如:

type FoobarInput struct {
	foo Fooer
	bar Barer
	msg string
}
input := FoobarInput{
		msg: "studyzy",
	}
	container.Register(func() Fooer { return &Foo{} })
	container.Register(func() Barer { return &Bar{} })
	err := container.Fill(&input)

结构体中的字段还支持tag,目前提供的tag有两种:

  • name //指定这个字段在获得对应的实例时使用的name
  • optional //指定这个字段是否是可选的,如果是,那么就算获得不到对应的实例,也不会报错。 示例example:
type FoobarInputWithTag struct {
	foo Fooer `optional:"true"`
	bar Barer `name:"baz"`
	msg string
}

2.2.6. 函数调用

除了构造函数注入之外,iocgo也支持函数注入,我们申明一个函数,这个函数的参数中有些参数是interface,那么通过调用iocgo中的Call方法,可以为这个函数注入对应的实例作为参数,并最终完成函数的调用。 示例 example:

func SayHi1(f Fooer, b Barer) {
	f.Foo(1234)
	b.Bar("hi")
}
Register(func() Fooer { return &Foo{} })
Register(func() Barer { return &Bar{} })
Call(SayHi1)

Call函数也是支持选项的,目前提供了2个选项:

  • CallArguments 指定函数中某个参数的值
  • CallDependsOn 指定函数中某个参数在通过ioc容器获得实例时使用哪个name来获得实例。 最后函数调用完成,如果函数本身有多个返回值,有error返回,那么Call函数也会返回对应的结果。

2.3 参考:

在写这个iocgo的代码时,主要参考了以下两个Ioc相关的项目:

3. 总结

iocgo是一个纯Golang语言开发的用于管理依赖注入的IoC容器,使用这个容器可以很好的实现go语言下的面向对象开发,模块解耦。现已经开源,欢迎大家使用,开源地址:https://github.com/studyzy/iocgo

以上就是Golang轻量级IoC容器安装使用示例的详细内容,更多关于Golang轻量级IoC容器的资料请关注我们其它相关文章!

(0)

相关推荐

  • Go标准容器之Ring的使用说明

    简介 Go的标准包Container中包含了常用的容器类型,包括conatiner/list,container/heap,container/ring,本篇讲解container/ring的使用. ring包 ring包提供了环形链表的操作.它仅导出了一个类型,Ring: // Ring表示环形链表中的元素. type Ring struct { Value interface{} // Value类型为interface{},因此可以接受任意类型 } // 创建一个长度为n的环形链表 fun

  • docker django无法访问redis容器的解决方法

    docker-compose.yal文件中: redis: image: redis container_name: xdemo.redis ports: - 6379:6379 restart: always django setting.py中配置redis: CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache', 'LOCATION': 'redis://127.0.0.1:6379', "OPTIONS&qu

  • golang实现对docker容器心跳监控功能

    自己写的go程序放到线上本来编译成二进制扔上去就行啦,但是怀着一颗docker的心,最终还是将它放到docker容器中运行起来了,运行起来也ok,一个最小容器64M,统一管理起来也方便,但是毕竟是个线上长驻内存的服务程序,万一跑挂了怎么办,如何才能监控它,直接上go代码,网上代码,略微做了下注释,但实测过,真实有效: package main import ( "encoding/json" "errors" "flag" "fmt&q

  • Go 容器遍历的实现示例

    前文回顾 前面的文章主要介绍了 Go 语言中提供了 list 列表和 Map 映射关系容器,这两种容器都是我们日常经常使用到的.介绍了好多种的 Go 语言提供的基础容器,免不了要查询容器中的数据,那么是如何实现遍历的呢?本文将会介绍几种常用容易的遍历及其使用. 容器遍历 Go 语言中 range 关键字用于 for 循环中迭代数组(array).切片(slice).通道(channel)或集合(map)的元素.在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对.

  • Golang: 内建容器的用法

    1.数组 数组是值类型 [10]int 和 [20]int是不同类型 调用func(arr [10]int)会拷贝数组 在go语言中一般不直接使用数据 package main import "fmt" func updateArr(arr *[5]int) { arr[0] = 100 } func updateArrThroughSlice(arr []int) { arr[0] = 100 } func main() { //创建一个数据 var arr [5]int arr2

  • Golang轻量级IoC容器安装使用示例

    目录 1. iocgo简介 2. iocgo如何使用 2.1 iocgo包的安装 2.2 使用示例与说明 2.2.1 最简单的例子: 2.22. Register 的选项 2.2.3. 注册实例 2.2.4. 获得实例 2.2.5. 结构体参数和字段填充 2.2.6. 函数调用 2.3 参考: 3. 总结 1. iocgo简介 习惯于Java或者C#开发的人应该对控制反转与依赖注入应该再熟悉不过了.在Java平台有鼎鼎大名的Spring框架,在C#平台有Autofac,Unity,Windsor

  • Laravel 5.4向IoC容器中添加自定义类的方法示例

    IoC 容器 容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器.一个容器能够装什么,全部取决于你对该容器的定义.当然,有这样一种容器,它存放的不是文本.数值,而是对象.对象的描述(类.接口)或者是提供对象的回调,通过这种容器,我们得以实现许多高级的功能,其中最常提到的,就是 "解耦" ."依赖注入(DI)". IoC 容器 -- Laravel 的核心 Laravel 的核心就是一个 IoC 容器,根据文档,称其为"服务容器"

  • 用java的spring实现一个简单的IOC容器示例代码

    要想深入的理解IOC的技术原理,没有什么能比的上我们自己实现它.这次我们一起实现一个简单IOC容器.让大家更容易理解Spring IOC的基本原理. 这里会涉及到一些java反射的知识,如果有不了解的,可以自己去找些资料看看. 注意 在上一篇文章,我说,启动IOC容器时,Spring会将xml文件里面配置的bean扫描并实例化,其实这种说法不太准确,所以我在这里更正一下,xml文件里面配置的非单利模式的bean,会在第一次调用的时候被初始化,而不是启动容器的时候初始化.但是我们这次要做的例子是容

  • golang连接redis库及基本操作示例过程

    目录 Redis介绍 Redis支持的数据结构 Redis应用场景 准备Redis环境 go-redis库 安装 连接 V8新版本相关 连接Redis哨兵模式 连接Redis集群 基本使用 HVals set/get示例 zset示例 根据前缀获取Key 执行自定义命令 按通配符删除key Pipeline 事务 Watch Redis介绍 Redis是一个开源的内存数据库,Redis提供了多种不同类型的数据结构,很多业务场景下的问题都可以很自然地映射到这些数据结构上.除此之外,通过复制.持久化

  • Golang 官方依赖注入工具wire示例详解

    目录 依赖注入是什么 开源选型 wire providers injectors 类型区分 总结 依赖注入是什么 Dependency Injection is the idea that your components (usually structs in go) should receive their dependencies when being created. 在 Golang 中,构造一个结构体常见的有两种方式: 在结构体初始化过程中,构建它的依赖: 将依赖作为构造器入参,传入进

  • 浅析Java的Spring框架中IOC容器容器的应用

    Spring容器是Spring框架的核心.容器将创建对象,它们连接在一起,配置它们,并从创建到销毁管理他们的整个生命周期.在Spring容器使用依赖注入(DI)来管理组成应用程序的组件.这些对象被称为Spring Beans. 容器获得其上的哪些对象进行实例化,配置和组装通过阅读提供的配置元数据的说明.配置元数据可以通过XML,Java注释或Java代码来表示.下面的图是Spring如何工作的高层次图. Spring IoC容器是利用Java的POJO类和配置元数据的产生完全配置和可执行的系统或

  • 浅谈Spring IoC容器的依赖注入原理

    本文介绍了浅谈Spring IoC容器的依赖注入原理,分享给大家,具体如下: IoC容器初始化的过程,主要完成的工作是在IoC容器中建立 BeanDefinition 数据映射,并没有看到IoC容器对Bean依赖关系进行注入, 假设当前IoC容器已经载入用户定义的Bean信息,依赖注入主要发生在两个阶段 正常情况下,由用户第一次向IoC容器索要Bean时触发 但我们可以在 BeanDefinition 信息中通过控制 lazy-init 属性来让容器完成对Bean的预实例化,即在初始化的过程中就

  • 详解如何实现Laravel的服务容器的方法示例

    1. 容器的本质 服务容器本身就是一个数组,键名就是服务名,值就是服务. 服务可以是一个原始值,也可以是一个对象,可以说是任意数据. 服务名可以是自定义名,也可以是对象的类名,也可以是接口名. // 服务容器 $container = [ // 原始值 'text' => '这是一个字符串', // 自定义服务名 'customName' => new StdClass(), // 使用类名作为服务名 'StdClass' => new StdClass(), // 使用接口名作为服务名

  • Spring为IOC容器注入Bean的五种方式详解

    这篇文章主要介绍了Spring为IOC容器注入Bean的五种方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一 @Import导入组件,id默认是组件的全类名 //类中组件统一设置.满足当前条件,这个类中配置的所有bean注册才能生效: @Conditional({WindowsCondition.class}) @Configuration @Import({Color.class,Red.class,MyImportSelector

  • Golang学习笔记之安装Go1.15版本(win/linux/macos/docker安装)

    安装Go1.15版本 大纲 Windows安装GoLinux安装GoMacOS安装GoDocker安装Go总结 视频地址:https://www.bilibili.com/video/BV14a4y177XG?p=3 Windows安装Go 1.点击下载go1.15版本的msi安装包 64位系统 https://studygolang.com/dl/golang/go1.15.windows-amd64.msi 32位系统 https://studygolang.com/dl/golang/go

随机推荐