本文对Dubbo 3多实例改造后编码相关变化进行一个简单的总结。
从只有ApplicationModel,新增 ScopeModel/FrameworkModel/ModuleModel 表达多实例的层次模型。 每个ScopeModel实例都会创建并绑定属于自己的重要成员:
ScopeModel 作为最基础的模型,可以在SPI/Bean/URL 等持有和传递。
SPI 注解添加scope属性,标记其所属的作用域。 ExtensionScope 与层次模型对应关系:
�
新增ExtensionDirector用于实现多层级的spi管理及依赖注入。
ExtensionDirector spi extension 创建流程如下:
Scope 作用范围如下图: 上层对象可以注入本层及下层的SPI/Bean对象,下层对象不能注入上层的SPI/Bean对象。
新增ScopeBeanFactory用于内部Bean托管,支持在多个不同模块中共享一个实例对象。 ScopeBeanFactory 也支持scope,注入规则与ExtensionDirector相同。 用法请参考:FrameworkStatusReportService、RemoteMetadataServiceImpl、MetadataReportInstance
将原来的ServiceRepository拆分为3个类,分别对应3个层次的模型。 FrameworkServiceRepository �ServiceRepository ModuleServiceRepository � 将服务接口信息ProviderModel/ConsumerModel/ServiceDescriptor 注册到ModuleServiceRepository 中,同时在FrameworkServiceRepository 保存一份映射,用于根据请求查找对应的服务接口模型。
原方法:ApplicationModel 提供了一系列静态方法用于获取共享应用实例的数据
ApplicationModel.getConfigManager()
ApplicationModel.getEnvironment()
ApplicationModel.getServiceRepository()
ApplicationModel.getExecutorRepository()
ApplicationModel.getName()
新办法:先找到ApplicationModel实例,然后通过实例的方法获取数据
// 获取默认实例,兼容原来的单应用实例
ApplicationModel.defaultModel().getApplicationEnvironment();
// 根据Module获取ApplicationModel
moduleModel.getApplicationModel();
// 通过URL获取ApplicationModel
ScopeModelUtil.getApplicationModel(url.getScopeModel());
// 通过Config配置类获取
ScopeModelUtil.getApplicationModel(serviceConfig.getScopeModel());
// SPI/Bean 可通过构造函数注入
public ConfigManager(ApplicationModel applicationModel) {
this.applicationModel = applicationModel;
}
// SPI/Bean 通过实现ScopeModelAware接口注入
public class DefaultGovernanceRuleRepositoryImpl implements GovernanceRuleRepository, ScopeModelAware {
private ApplicationModel applicationModel;
@Override
public void setApplicationModel(ApplicationModel applicationModel) {
this.applicationModel = applicationModel;
}
// ...
}
// 枚举FrameworkModel的所有Application
for (ApplicationModel applicationModel : frameworkModel.getApplicationModels()) {
List<RegistryProtocolListener> listeners = applicationModel.getExtensionLoader(RegistryProtocolListener.class)
.getLoadedExtensionInstances();
if (CollectionUtils.isNotEmpty(listeners)) {
for (RegistryProtocolListener listener : listeners) {
listener.onDestroy();
}
}
}
// 枚举所有FrameworkModel
for (FrameworkModel frameworkModel : FrameworkModel.getAllInstances()) {
destroyProtocols(frameworkModel);
}
原方法:是通过静态方法 ExtensionLoader.getExtensionLoader() 获取
ExtensionLoader.getExtensionLoader(Cluster.class).getExtension(name, wrap);
新方法:通过ScopeModel或者ExtensionDirector获取
applicationModel.getExtensionLoader(Cluster.class).getExtension(name, wrap);
原方法:通过uniqueServiceName来在ServiceRepository 中lookup 服务模型
新方法:通过URL传递ScopeModel/ServiceModel,请参考RegistryProtocol
原方法:通过静态变量保存bean实例
新方法:通过BeanFactory共享实例
根据ScopeModel获取某个层次的Model,已经做了兼容处理,scopeModel参数为null时返回默认实例: ScopeModelUtil.getFrameworkMode(scopeModel) ScopeModelUtil.getApplicationMode(scopeModel) ScopeModelUtil.getModuleMode(scopeModel)
1、ExtensionLoader.getExtensionLoader() 2、Application.defaultModel() 或者其它静态方法 3、在Framework层获取Application层的对象,如在Protocol中处理Application数据,QOS中遍历所有Application数据,请参考RegistryProtocol。 4、在静态方法中访问默认实例的数据 5、静态变量的bean实例、cache 6、SPI接口中静态方法访问数据,可能要拆分为干净的SPI和Bean,请参考FrameworkStatusReportService/FrameworkStatusReporter。 7、可能某些URL还没有改造,需要在创建时设置ServiceModel/ScopeModel