Dubbo 3.2版本分析Provider启动前的前菜
写在前面例子分析设置 application设置 registry设置 protocol设置 serviceConfig
小结
写在前面
一直以来对Dubbo的实现原理颇为好奇,前几个月在Dubbo专栏里也陆续写了几遍文章,奈何自身原因+客观原因,就没有坚持下来。这次重启Dubbo源码刨析系列,也刚好可以借着2023年7月发布的比较新的Dubbo 3.2版本源码进行学习研究,共勉!
例子
这里我们还是以provider启动的Demo为入口,进行分析:
如下,为Dubbo服务暴漏出来的接口:
public interface DemoService {
String sayHello(String name);
}
DemoServiceImpl为Dubbo provider
public class DemoServiceImpl implements DemoService {
private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
@Override
public String sayHello(String name) {
logger.info("Hello " + name + ", request from consumer: "
+ RpcContext.getServiceContext().getRemoteAddress());
return "Hello " + name + ", response from provider: "
+ RpcContext.getServiceContext().getLocalAddress();
}
}
Application为服务的启动类
public class Application {
private static final String REGISTRY_URL = "zookeeper://sr-1-zk-cluster-1.gz.cvte.cn:2181";
public static void main(String[] args) {
startWithBootstrap();
}
private static void startWithBootstrap() {
ServiceConfig
service.setInterface(DemoService.class);
service.setRef(new DemoServiceImpl());
DubboBootstrap bootstrap = DubboBootstrap.getInstance();
bootstrap
.application(new ApplicationConfig("dubbo-api-provider"))
.registry(new RegistryConfig(REGISTRY_URL))
.protocol(new ProtocolConfig(CommonConstants.DUBBO, -1))
.service(service)
.start()
.await();
}
}
分析
在服务正式启动前(**start **方法),需要设置上下文 **application ,**接着配置注册中心地址信息 **registry ,**最后设置我们的 provider service 服务信息。
bootstrap
.application(new ApplicationConfig("dubbo-api-provider"))
.registry(new RegistryConfig(REGISTRY_URL))
.protocol(new ProtocolConfig(CommonConstants.DUBBO, -1))
.service(service)
.start()
设置 application
关于 **application **方法,通过 debug 我们可以发现如下的一段的代码,这里有一个关于支持的配置类型的判断方法:isSupportConfigType,可以发现目前支持的配置有如下9种。
org.apache.dubbo.config.ApplicationConfigorg.apache.dubbo.config.MonitorConfigorg.apache.dubbo.config.MetricsConfigorg.apache.dubbo.config.SslConfigorg.apache.dubbo.config.ProtocolConfigorg.apache.dubbo.config.RegistryConfigclass org.apache.dubbo.config.ConfigCenterConfigorg.apache.dubbo.config.MetadataReportConfigorg.apache.dubbo.config.TracingConfig 这里是设置 **application,**对应的 config 类型很明显是 org.apache.dubbo.config.ApplicationConfig。然后是对 **scopeModel 参数的判断,**官网对这个参数又叫做领域模型。
根据官网的文档描述,Dubbo3中引入“模型的概念”来进行服务级别的管理工作,像配置中心和元数据中心的管理。而这么做的原因,也有着对应的解释:
让Dubbo支持多应用的部署,这块一些大企业有诉求从架构设计上,解决静态属性资源共享、清理的问题分层模型将应用的管理和服务的管理分开
执行**configsCache.computeIfAbsent,configsCache **类型为 Map
public final
if (config == null) {
return null;
}
// ignore MethodConfig
if (!isSupportConfigType(config.getClass())) {
throw new IllegalArgumentException("Unsupported config type: " + config);
}
if (config.getScopeModel() != scopeModel) {
config.setScopeModel(scopeModel);
}
Map
configsCache.computeIfAbsent(getTagName(config.getClass()), type -> new ConcurrentHashMap<>());
// fast check duplicated equivalent config before write lock
if (!(config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase)) {
for (AbstractConfig value : configsMap.values()) {
if (value.equals(config)) {
return (T) value;
}
}
}
// lock by config type
synchronized (configsMap) {
return (T) addIfAbsent(config, configsMap);
}
}
设置 registry
和设置 application异曲同工之妙,这里同样先设置领域模型,负责管理我们的配置中心,接着往我们的 **configManager **添加注册中心。addRegistry方法里,调用的还是我们上面代码的 addConfig 方法,只不过这次这里参数 config 的配置类型是org.apache.dubbo.config.RegistryConfig。由于 configsMap 没有存在对应的注册信息,最终会进入 synchronized区域,往我们的 configsCache添加注册信息,如图1所示。
public DubboBootstrap registry(RegistryConfig registryConfig) {
registryConfig.setScopeModel(applicationModel);
configManager.addRegistry(registryConfig);
return this;
}
图1
设置 protocol
这里我们采用的是 dubbo 协议,在服务启动时指定:new ProtocolConfig(CommonConstants.DUBBO, -1)。同样先设置领域模型,然后添加协议配置信息。配置类型为 **org.apache.dubbo.config.ProtocolConfig **然后执行 **addProtocol **方法,本质还是执行 **addConfig 方法。最终添加配置后, configsCache **信息,如图2所示。
public DubboBootstrap protocols(List
if (CollectionUtils.isEmpty(protocolConfigs)) {
return this;
}
for (ProtocolConfig protocolConfig : protocolConfigs) {
protocolConfig.setScopeModel(applicationModel);
configManager.addProtocol(protocolConfig);
}
return this;
}
图2
设置 serviceConfig
不同于前面的注册中心等公共配置的操作,serviceConfig 的添加通过 getConfigManager() 方法返回的时ModuleConfigManager 类的实例。前面的注册中心等公共配置的添加,是通过 ConfigManager类的实例去操作,关于 ConfigManager 和ModuleConfigManager,我们可以看图3的类结构图。兜兜转转,还是来到 AbstractConfigManager 的 addConfig方法。关于它的实现已经在上面展示。这里传入的 config 类型是 org.apache.dubbo.config.ServiceConfig。如图4,最终还是会通过 configCache创建 key 为 “service”,value 为 serviceConfig 的实例。注意,这里的 configCache 为 ModuleConfigManager 的成员变量。而前面的注册中心等公共配置的操作,最终添加到的 configCache 为 ConfigManager 类的成员变量。
public DubboBootstrap service(ServiceConfig> serviceConfig) {
this.service(serviceConfig, applicationModel.getDefaultModule());
return this;
}
public DubboBootstrap service(ServiceConfig> serviceConfig, ModuleModel moduleModel) {
serviceConfig.setScopeModel(moduleModel);
moduleModel.getConfigManager().addService(serviceConfig);
return this;
}
public void addService(ServiceConfigBase> serviceConfig) {
addConfig(serviceConfig);
}
图3 图4
小结
本文对 Dubbo 3.2 源码 provider 启动前进行的操作做了大概的梳理,可以知道大体流程还是遵循原来的设计,设置 application -> 设置 registry -> 设置 protocol -> 设置 serviceConfig 。但在具体实现上跟原来版本也有所区别,比如引入了领域模型进行分层次管理。下一篇文章,我们将分析 Dubbo 3.2 源码 provider 具体的启动流程。
推荐链接
发表评论