项目背景
设计思路
应用开发思路
IOC-golang 可以帮助开发者更清晰地“构造一个对象” 在使用IOC-golang 开发的过程中,开发者只需要将参数、依赖对象、初始化逻辑这三要素通过注解或标签的形式标注在代码中,即可完成一个结构的定义,完全无需关心结构的拼装过程和依赖对象的创建过程,让开发者专注于当前结构的业务逻辑。
// +ioc:autowire=true
// +ioc:autowire:type=normal
// +ioc:autowire:paramType=Config
// +ioc:autowire:constructFunc=New
type RedisClient struct {
client *redis.Client
ServiceImpl1 Service `singleton:'main.ServiceImpl1'` // inject Service 's ServiceImpl1
}
type Config struct {
Address string
Password string
DB string
}
func (c *Config) New(impl *Impl) (*Impl, error) {
dbInt, err := strconv.Atoi(c.DB)
if err != nil {
return impl, err
}
client := redis.NewClient(&redis.Options{
Addr: c.Address,
Password: c.Password,
DB: dbInt,
})
_, err = client.Ping().Result()
if err != nil {
return impl, err
}
impl.client = client
return impl, nil
}
IOC-golang 可以帮助开发者管理设计模型
// +ioc:autowire=true
// +ioc:autowire:type=singleton
type App struct {
ServiceImpl1 Service `singleton:'main.ServiceImpl1'` // inject Service 's ServiceImpl1 implementation
RedisClientPtr *RedisClient `normal:',address=localhost:6379&db=0'` // inject RedisClient struct pointer
}
如果按照常规的开发方式,开发者需要额外手动读取参数并创建依赖的 RedisClient 对象,手动组装 APP对象,维护单例模型指针,提供单例模型的构造函数等,这些逻辑都被 IOC-golang 封装好了。
对象生命周期
结构定义 结构提供者编写结构的字段与函数。 参数传入与依赖对象加载 对象创建的准备阶段,获取到依赖的参数,获取到所有依赖的下游对象。 对象创建与初始化 对象的组装过程,组装完成后执行必要的初始化逻辑。 对象使用 对象的函数被使用者调用 对象销毁 对象被销毁
结构开发者视角:(撰写产品说明书) 我负责定义结构的字段和函数 我负责明确依赖的下游对象、依赖的参数字段。 我负责明确参数应该从哪里加载,例如:从标签加载,从配置中某个位置加载,从 API 传入的参数中加载。 我负责明确结构的依赖注入模型,比如单例模型。 我负责定义对象的初始化逻辑 我负责定义对象的销毁逻辑
结构使用者视角:(阅读产品说明书,按照说明书的内容使用结构) 我负责明确要使用哪个结构。(找到对应的产品说明书) 我负责使用一种“产品说明书”中支持的自动装载模型,例如:单例模型。 我负责明确“产品说明书”中给定的结构依赖参数。 我负责使用一种“产品说明书”里支持的参数加载方式,来加载结构依赖参数,加载方式可能包括:从标签加载,从配置中某个位置加载,从 API 传入的参数中加载。 我负责使用一种对象获取方式,来获取对象实例,例如:通过 API 获取,通过标签注入获取。 我负责调用对象函数。 我负责触发对象销毁逻辑。
可扩展性
对象的可扩展性 对象的可扩展性,即针对确定的一个结构(非单例),你可以通过传入不同的参数来获取多个期望的对象。这个过程往往被结构使用者关注,他需要思考如何传入参数,获得对象,调用对象从而实现正确的业务逻辑。通过这一可扩展性,结构使用者可以扩展出多个对象实例。
结构的可扩展性 结构的可扩展性,即针对一个确定的自动装载模型,你可以通过定义自己的结构描述信息,将你的结构体注册在框架上,以供使用。这个过程是结构提供者关心的,他需要思考选用哪个自动装载模型,思考提供的结构的全部生命周期信息。通过这一可扩展性,结构提供者可以为框架注入多种多样的结构,这些结构都会按照被选择的自动装载模型执行加载逻辑。 框架提供了一些预置的结构,例如 redis 客户端、gorm客户端等等,开发者可以直接传入参数,注入或通过API获取,直接使用,但这些预置的结构一定无法覆盖业务需求的。开发者注册自己的任何结构到框架上,都是使用了结构的可扩展性,这些被注册的结构和框架提供的预置结构,都是同一层面的概念。
自动装载模型的可扩展性 自动装载模型描述了一类结构的装载方式,例如是否单例模型、参数从哪里加载、注入标签应该符合什么格式等等。这个过程也是结构提供者关心的。 框架提供了一些预置的自动装载模型,例如单例模型、多例模型、配置模型、rpc 模型等,开发者可以根据按照业务需要,将一个或多个结构注册在期望的自动装载模型上,当已有的自动装载模型不足以适配业务场景,开发者可以调用API进行定制化。
小结
一个问题:一个对象如何被创建。 两个角度:结构开发者视角,结构使用者视角。 三个维度扩展:自动装载模型、结构、对象。
项目层级与功能
项目层级
主要功能
// +ioc:autowire=true
// +ioc:autowire:type=singleton
type App struct {
ServiceImpl1 ServiceInterface `singleton:'main.ServiceImpl1'` // inject ServiceInterface 's ServiceImpl1 implementation
}
// +ioc:autowire=true
// +ioc:autowire:type=singleton
type App struct {
NormalDB3Redis normalRedis.ImplIOCInterface `normal:',address=127.0.0.1:6379&db=3'`
}
通过 API 进行参数传递:
func main() {
client := redis.NewClient(&redis.Options{
Addr: p.RedisAddr,
})
}
结构代理层:AOP
// +ioc:autowire=true
// +ioc:autowire:type=singleton
type Impl1 struct {
}
func (i *Impl1) Hello(req string) string {
return req
}
开发者可以通过执行iocli gen命令,一键为工程内所有标注的结构生成代码,生成位于结构相同目录的zz_generated.ioc.go,其内容包括:
结构注册代码,会以结构描述符的形式,将结构生命周期注册到框架上。
func init() {
singleton.RegisterStructDescriptor(&autowire.StructDescriptor{
Factory: func() interface{} {
return &Impl1{}
},
})
}
type Impl1IOCInterface interface {
Hello(req string) string
}
// 获取结构指针
func GetImpl1() (*Impl1, error) {
i, err := singleton.GetImpl(util.GetSDIDByStructPtr(new(Impl1)), nil)
if err != nil {
return nil, err
}
impl := i.(*Impl1)
return impl, nil
}
// 获取包装了代理层的专属接口
func GetImpl1IOCInterface() (Impl1IOCInterface, error) {
i, err := singleton.GetImplWithProxy(util.GetSDIDByStructPtr(new(Impl1)), nil)
if err != nil {
return nil, err
}
impl := i.(Impl1IOCInterface)
return impl, nil
}
愿景
IOC-golang 是一个崭新的项目,从第一行代码的编写,到今天不过一个月的时间。
我们的愿景是让 IOC-golang 成为 Go 应用开发的首选框架,让 Go 开发人员更贴近业务逻辑,减少冗余代码,增加代码的易读性,让 Go 生态的 “面向对象编程” 进入自动挡时代。
如何贡献
项目初创,十分期待能与感兴趣的开发者共创一片天地。
项目github地址: github.com/alibaba/ioc-golang
项目文档:ioc-golang.github.io
项目示例:ioc-golang/example
欢迎加入钉钉群“IOC-golang 交流群”:44638289
云原生环境下基于 Serverless 架构的创新应用