golang 依赖控制反转(IoC) 改进版

最近在开发基于golang下的cqrs框架 https://github.com/berkaroad/squat (陆续开发中,最近断了半年,懒了。。。)。这个框架依赖ioc框架,因为之前写了一个ioc,所以借此完善下,主要从灵活性、易用性、性能角度进行了优化。顺带也支持了go mod,并将源码文件合并为单文件,方便有直接移植源码的人(license信息请保留,尊重著作权)。

先来个直观的调用端对比(v1.2.0为新版,v0.1.1为旧版):

go 复制代码
var container = ioc.NewContainer() // v0.1.1
var container = ioc.New() // v1.2.0,非必需,可以直接使用ioc.XXX 即使用内置全局Container

// register service to *struct
container.Register(&Class2{Name: "Jerry Bai"}, ioc.Singleton) // v0.1.1
ioc.AddSingleton[*Class2](&Class2{Name: "Jerry Bai"}) // v1.2.0
container.Register(&Class1{}, ioc.Transient) // v0.1.1,调用函数InitFunc()获取初始化函数来完成初始化
ioc.AddTransient[*Class1](func() *Class1 { // v1.2.0,直接通过传入的函数来完成
    var svc Class1
    // inject to *struct
    ioc.Inject(&svc) // v1.2.0,支持注入到结构体
}

// register service to interface.
container.RegisterTo(&Class2{Name: "Jerry Bai"}, (*Interface2)(nil), ioc.Singleton) // v0.1.1
ioc.AddSingleton[Interface2](&Class2{Name: "Jerry Bai"}) // v1.2.0
container.RegisterTo(&Class1{}, (*Interface1)(nil), ioc.Transient) // v0.1.1,调用函数InitFunc()获取初始化函数来完成初始化
ioc.AddTransient[Interface1](func() Interface1 { // v1.2.0,直接通过传入的函数来完成
    var svc Class1
    // inject to *struct
    ioc.Inject(&svc) // v1.2.0,支持注入到结构体
}

// inject to function
ioc.Inject(func(c1 *Class1, c2 *Class2, i1 Interface1, i2 Interface2, resolver ioc.Resolver) { // v1.2.0
    println("c1.C2Name=", c1.C2.Name)
    println("c2.Name=", c2.Name)
    println("i1.GetC2Name=()", i1.GetC2Name())
    println("i2.GetName=()", i2.GetName())
})
container.Invoke(func(c1 *Class1, c2 *Class2, i1 Interface1, i2 Interface2, roContainer ioc.ReadonlyContainer) { // v0.1.1
    println("c1.C2Name=", c1.C2Name)
    println("c2.Name=", c2.Name)
    println("i1.GetC2Name=()", i1.GetC2Name())
    println("i2.GetName=()", i2.GetName())
})

新版本,从功能角度,增加支持了结构体注入、泛型方式获取服务实例、替换已存在的服务。

go 复制代码
// get service from ioc(go1.18开始支持泛型)
c1 := ioc.GetService[*Class1]
c2 := ioc.GetService[*Class2]
i1 := ioc.GetService[Interface1]
i2 := ioc.GetService[Interface2]
go 复制代码
// override exists service(一般用于覆盖默认注入的对象)
c := ioc.New()
ioc.SetParent(c)
ioc.AddSingletonToC[Interface3](c, &Class3{Name: "Jerry Bai"}) // add service to parent's container
i3 := ioc.GetService[Interface3]() // *Class3, 'Interface3' only exists in parent's container
ioc.AddSingleton[Interface3](&Class4{Name: "Jerry Bai"}) // add service to global's container
i3 = ioc.GetService[Interface3]() // *Class4, 'Interface3' exists in both global and parent's container

对结构体初始化的函数定义(模拟构造函数),从固定获取函数的接口 interface{InitFunc() interface{}} 改为按函数名获取(默认为 Initialize)。

go 复制代码
type Class2 struct {
    Name     string
    resolver ioc.Resolver
}

func (c *Class2) Initialize(resolver ioc.Resolver) string {
    c.resolver = resolver
    return c.Name
}

type Class3 struct {
    Name     string
    resolver ioc.Resolver
}

// specific custom initialize method name
func (c *Class3) InitializeMethodName() string {
    return "MyInitialize"
}

// custom initialize method
func (c *Class3) MyInitialize(resolver ioc.Resolver) string {
    c.resolver = resolver
    return c.Name
}

以下是新版本的性能测试。带 "Native" 的为原生调用,具体测试代码,参见源码:https://github.com/berkaroad/ioc/blob/master/benchmark_test.go

go test -run=none -count=1 -benchtime=1000000x -benchmem -bench=. ./...

goos: linux
goarch: amd64
pkg: github.com/berkaroad/ioc
cpu: AMD Ryzen 7 5800H with Radeon Graphics         
BenchmarkGetSingletonService-4           1000000                26.16 ns/op            0 B/op          0 allocs/op
BenchmarkGetTransientService-4           1000000               370.9 ns/op            48 B/op          1 allocs/op
BenchmarkGetTransientServiceNative-4     1000000               131.9 ns/op            48 B/op          1 allocs/op
BenchmarkInjectToFunc-4                  1000000               659.5 ns/op           144 B/op          5 allocs/op
BenchmarkInjectToFuncNative-4            1000000                89.26 ns/op            0 B/op          0 allocs/op
BenchmarkInjectToStruct-4                1000000               311.7 ns/op             0 B/op          0 allocs/op
BenchmarkInjectToStructNative-4          1000000                87.64 ns/op            0 B/op          0 allocs/op
PASS
ok      github.com/berkaroad/ioc        1.686s

---------------------------------分割线-------------------------------------------------------------

我的ioc项目,已经挂在github上,有兴趣的可以去了解下。https://github.com/berkaroad/ioc

使用中有何问题,欢迎在github上给我提issue,谢谢!

相关推荐
ifanatic2 小时前
[面试]-golang基础面试题总结
面试·职场和发展·golang
懒是一种态度2 小时前
Golang 调用 mongodb 的函数
数据库·mongodb·golang
XINGTECODE3 小时前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
入 梦皆星河3 小时前
在 Ubuntu/Debian 上安装 Go
ubuntu·golang·debian
凡人的AI工具箱3 小时前
15分钟学 Go 第 60 天 :综合项目展示 - 构建微服务电商平台(完整示例25000字)
开发语言·后端·微服务·架构·golang
007php00717 小时前
GoZero 上传文件File到阿里云 OSS 报错及优化方案
服务器·开发语言·数据库·python·阿里云·架构·golang
高 朗18 小时前
【GO基础学习】基础语法(2)切片slice
开发语言·学习·golang·slice
IT书架18 小时前
golang面试题
开发语言·后端·golang
醒过来摸鱼1 天前
【Golang】协程
开发语言·后端·golang
灼华十一1 天前
算法编程题-排序
数据结构·算法·golang·排序算法