dubbo-go
dubbo-go copied to clipboard
Solve configuration circular dependencies
Why is this needed: 这个issue由之前的提案(#2375)引出,拆分出client模块后,为了让NewClient可以完全与config.Load等价,还需要注入config.RootConfig和config.ConsumerConfig,以完成ReferenceConfig.Init流程。但config模块也会依赖client模块,这样就造成了循环依赖。根本原因在于config模块中的大部分配置都会直接感知上层配置,以client侧的Root->Consumer->Reference配置结构为例,ReferenceConfig.Init(rc *RootConfig)中会直接引用RootConfig和ConsumerConfig。
What would you like to be added: 为了达到上层模块依赖下层模块,下层模块感知不到上层模块的效果,考虑将ReferenceConfig.Init(rc *config.RootConfig)改成ReferenceConfig.Init(opts ...ReferenceOption),ConsumerConfig.Init在调用client.ReferenceConfig.Init时,将所需的配置都以client.ReferenOption数组的形式传入。以下是代码转变:
// old code
func (cc *ConsumerConfig) Init(rc *RootConfig) error {
// 省略
for key, referenceConfig := range cc.References {
if err := referenceConfig.Init(rc); err != nil {
return err
}
}
// 省略
}
// new code
func (cc *ConsumerConfig) Init(rc *RootConfig) error {
// 省略
cc.refOpts = []client.ReferenceOption{
client.WithFilter(cc.Filter),
client.WithRegistryIDs(cc.RegistryIDs),
client.WithProtocol(cc.Protocol),
client.WithTracingKey(cc.TracingKey),
client.WithCheck(cc.Check),
client.WithMeshEnabled(cc.MeshEnabled),
client.WithAdaptiveService(cc.AdaptiveService),
client.WithProxyFactory(cc.ProxyFactory),
}
for key, referenceConfig := range cc.References {
if err := referenceConfig.Init(cc.refOpts...); err != nil {
return err
}
}
// 省略
}
Extended 将ReferenceConfig移动到client模块,config模块依赖client模块可以引申到其他配置,将这些配置移动到各自的模块,例如将RegistryConfig移动到registry模块中,config模块依赖registry模块。这部分的工作将和#2343 dubbo模块拆解与重构计划直接挂钩。
依赖确实有点容易循环,有些模块会把一模一样的配置再拷贝一个 struct 出来,只是为了避免循环依赖,例如 https://github.com/apache/dubbo-go/blob/bf5f2ddf40eaf9779355a692bab7842e290b54b2/config/metric_config.go#L45C55-L45C55, 是不是可以考虑做彻底点,把 config 只作为被依赖方,不再依赖其他模块
依赖确实有点容易循环,有些模块会把一模一样的配置再拷贝一个 struct 出来,只是为了避免循环依赖,例如 https://github.com/apache/dubbo-go/blob/bf5f2ddf40eaf9779355a692bab7842e290b54b2/config/metric_config.go#L45C55-L45C55, 是不是可以考虑做彻底点,把 config 只作为被依赖方,不再依赖其他模块
config包之前做为项目入口一直是顶层模块,如果不依赖其他模块,config.Load这一套启动流程没法保证。我的想法是config包做为顶层模块,把配置都往下传,层次较低的模块只看配置,不感知config包。
而且除了config包,extension包也有循环依赖的问题,我们应该梳理一下整体的依赖情况,尽量保证自顶向下依赖的逻辑是通顺的。
把配置都往下传
是怎么个传法,用 url ?
把配置都往下传
是怎么个传法,用 url ?
- 直接依赖,使用Init(opts ...option)方式把参数注入进去 比如ConsumerConfig依赖ReferenceConfig,之前是Init(rc *RootConfig),现在是Init(opts ...ReferenceOption)。这个需要我们对dubbo-go做好分层。
- invoker链串联 使用URL传静态配置(config.Load时完成的所有配置),使用Invocation传动态配置(invoker链执行时查看)。invocation目前已经可以传复杂配置,URL也需要支持类似map[string]interface{}的复杂配置。每个invoker内部只管传进来的配置,不去config包拿。
sounds good
把配置都往下传
是怎么个传法,用 url ?
- 直接依赖,使用Init(opts ...option)方式把参数注入进去 比如ConsumerConfig依赖ReferenceConfig,之前是Init(rc *RootConfig),现在是Init(opts ...ReferenceOption)。这个需要我们对dubbo-go做好分层。
- invoker链串联 使用URL传静态配置(config.Load时完成的所有配置),使用Invocation传动态配置(invoker链执行时查看)。invocation目前已经可以传复杂配置,URL也需要支持类似map[string]interface{}的复杂配置。每个invoker内部只管传进来的配置,不去config包拿。