你可能还想看
1. 龙蜥社区成立云原生SIG,引入3大核心技术
2. 阿里云中间件的开源往事
3. 中国工程院院士郑纬民:我对中国在下一个 IT 时代拥有一席之地很乐观
4. 技术人 | 优秀代码真的不需要注释吗?
5. 阿里云容器服务负责人易立:云原生如何解企业降本提效难题?
关注我们
欢迎关注加星标✨ 每日推送不错过
凌云时刻
项目背景
设计思路
// +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
}
如果按照常规的开发方式,开发者还需要要额外做这些事情:手动从配置文件读取 Config对象的所有字段,手动把 ServiceImpl1 对象创建出来,手动拼装 RedisClient 对象然后调用初始化逻辑。而这些通用的逻辑都被 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
}
结构定义
结构提供者编写结构的字段与函数。
参数传入与依赖对象加载
对象创建与初始化
对象使用
对象销毁
上述对象的生命周期,是站在对象的角度来观察的。我们还可以从结构开发者视角和结构使用者视角来观察。为了表述的更为形象,我们可以用 “产品说明书” 来比喻结构的全部信息。
上述的两个视角,是开发者在面向对象编程的开发过程中一定会考虑的。IOC-golang 框架在设计中明确了这两个视角。让一个结构的生命周期不再是一串面向过程的操作,而是两侧责任明确的开发模型。
结构的可扩展性
自动装载模型的可扩展性
// +ioc:autowire=true
// +ioc:autowire:type=singleton
type App struct {
ServiceStruct *ServiceStruct `singleton:""` // inject ServiceStruct struct pointer
}
将任何结构体注入至任何接口:
// +ioc:autowire=true
// +ioc:autowire:type=singleton
type App struct {
ServiceImpl1 ServiceInterface `singleton:"main.ServiceImpl1"` // inject ServiceInterface 's ServiceImpl1 implementation
}
可以通过 API 的方式,获取任何已注册的结构体:
// 该函数由 iocli 工具自动生成
func GetApp() (*App, error) {
i, err := singleton.GetImpl(util.GetSDIDByStructPtr(new(App)), nil)
if err != nil {
return nil, err
}
impl := i.(*App)
return impl, nil
}
灵活的参数传递能力
// +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,
})
}
通过配置进行参数写入:ioc_golang.yaml, 配置 github.com/alibaba/ioc-golang/extension/normal/nacos.Impl 结构的构造参数
autowire:
normal:
github.com/alibaba/ioc-golang/extension/normal/nacos.Impl:
my-nacos:
param:
nacosclientparam:
clientconfig:
appKey: appKey
serverconfigs:
- ipaddr: 127.0.0.1
port: 8848
结构代理层:AOP
本框架提供的 iocli 命令行工具会识别结构注解,从而生成注册代码、结构代理层、结构专属接口等信息,减少开发人员需要编写的代码量。
我们以这样一个结构为例:
// +ioc:autowire:type=singleton
type Impl1 struct {
}
func (i *Impl1) Hello(req string) string {
return req
}
func init() {
singleton.RegisterStructDescriptor(&autowire.StructDescriptor{
Factory: func() interface{} {
return &Impl1{}
},
})
}
type Impl1IOCInterface interface {
Hello(req string) string
}
结构代理层存根
type impl1_ struct {
Hello_ func(req string) string
}
func (i *impl1_) Hello(req string) string {
return i.Hello_(req)
}
// 获取结构指针
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 可以管理任何对象的代理存根,这也就意味着,我们可以用这一层代理做任何想做的事情。其中就包括框架已经实现的能力:
但这些只是“运维”这个庞大的话题的冰山一角,我们基于结构代理 AOP 层 ,可以做任何我们能想到的事情:
丰富的组件
在未来将会支持更丰富的常用 Go 开发 SDK,为开发者提供全家桶式的开发体验。
期待共创
项目文档:
项目示例:
欢迎关注加星标✨ 每日推送不错过