ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Dubbo 3.2版本分析Provider启动前的前菜

2026/8/8 19:25:33 拓冰建站 浏览量
Dubbo 3.2版本分析Provider启动前的前菜

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);@Overridepublic 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<DemoServiceImpl> service = new 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

  1. 关于 **application **方法,通过 debug 我们可以发现如下的一段的代码,这里有一个关于支持的配置类型的判断方法:isSupportConfigType,可以发现目前支持的配置有如下9种。
    • org.apache.dubbo.config.ApplicationConfig
    • org.apache.dubbo.config.MonitorConfig
    • org.apache.dubbo.config.MetricsConfig
    • org.apache.dubbo.config.SslConfig
    • org.apache.dubbo.config.ProtocolConfig
    • org.apache.dubbo.config.RegistryConfig
    • class org.apache.dubbo.config.ConfigCenterConfig
    • org.apache.dubbo.config.MetadataReportConfig
    • org.apache.dubbo.config.TracingConfig
  2. 这里是设置 **application,**对应的 config 类型很明显是 org.apache.dubbo.config.ApplicationConfig。
  3. 然后是对 **scopeModel 参数的判断,**官网对这个参数又叫做领域模型。

根据官网的文档描述,Dubbo3中引入“模型的概念”来进行服务级别的管理工作,像配置中心和元数据中心的管理。而这么做的原因,也有着对应的解释:

  • 让Dubbo支持多应用的部署,这块一些大企业有诉求
  • 从架构设计上,解决静态属性资源共享、清理的问题
  • 分层模型将应用的管理和服务的管理分开
  1. 执行**configsCache.computeIfAbsent,configsCache **类型为 Map<String, Map<String, AbstractConfig>>,为成员变量。调用 computeIfAbsent方法的时候,会判断key是否存在,存在则返回对应value,反之,先初始化value。
  2. 判断是否为消费端引用配置类型或者为服务端服务配置类型(这两种配置为我们应用服务相关的配置,需要保证动态更新)。如果不是上面两种配置,会从 configsMap 获取是否对应的配置类型,有则返回,因为这里我们是第一次启动服务,configsMap 的value为空的,所以为继续往下走。
  3. 最后进入 synchronized 锁区域,这里执行 addIfAbsent 方法,会把我们传入的config放到 configsCache中,注意!这里即使存在相同的key,也会进行覆盖更新。
public final <T extends AbstractConfig> T addConfig(AbstractConfig config) {if (config == null) {return null;}// ignore MethodConfigif (!isSupportConfigType(config.getClass())) {throw new IllegalArgumentException("Unsupported config type: " + config);}if (config.getScopeModel() != scopeModel) {config.setScopeModel(scopeModel);}Map<String, AbstractConfig> configsMap =configsCache.computeIfAbsent(getTagName(config.getClass()), type -> new ConcurrentHashMap<>());// fast check duplicated equivalent config before write lockif (!(config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase)) {for (AbstractConfig value : configsMap.values()) {if (value.equals(config)) {return (T) value;}}}// lock by config typesynchronized (configsMap) {return (T) addIfAbsent(config, configsMap);}}

设置 registry

  1. 和设置 application异曲同工之妙,这里同样先设置领域模型,负责管理我们的配置中心,接着往我们的 **configManager **添加注册中心。
  2. addRegistry方法里,调用的还是我们上面代码的 addConfig 方法,只不过这次这里参数 config 的配置类型是org.apache.dubbo.config.RegistryConfig。
  3. 由于 configsMap 没有存在对应的注册信息,最终会进入 synchronized区域,往我们的 configsCache添加注册信息,如图1所示。
public DubboBootstrap registry(RegistryConfig registryConfig) {registryConfig.setScopeModel(applicationModel);configManager.addRegistry(registryConfig);return this;}

图1
图1

设置 protocol

  1. 这里我们采用的是 dubbo 协议,在服务启动时指定:new ProtocolConfig(CommonConstants.DUBBO, -1)。
  2. 同样先设置领域模型,然后添加协议配置信息。配置类型为 **org.apache.dubbo.config.ProtocolConfig **然后执行 **addProtocol **方法,本质还是执行 **addConfig 方法最终添加配置后, configsCache **信息,如图2所示。
public DubboBootstrap protocols(List<ProtocolConfig> protocolConfigs) {if (CollectionUtils.isEmpty(protocolConfigs)) {return this;}for (ProtocolConfig protocolConfig : protocolConfigs) {protocolConfig.setScopeModel(applicationModel);configManager.addProtocol(protocolConfig);}return this;}

图2图2

设置 serviceConfig

  1. 不同于前面的注册中心等公共配置的操作,serviceConfig 的添加通过 getConfigManager() 方法返回的时ModuleConfigManager 类的实例
  2. 前面的注册中心等公共配置的添加,是通过 ConfigManager类的实例去操作,关于 ConfigManager 和ModuleConfigManager,我们可以看图3的类结构图。
  3. 兜兜转转,还是来到 AbstractConfigManageraddConfig方法。关于它的实现已经在上面展示。这里传入的 config 类型是 org.apache.dubbo.config.ServiceConfig。
  4. 如图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
图3

图4
图4

小结

本文对 Dubbo 3.2 源码 provider 启动前进行的操作做了大概的梳理,可以知道大体流程还是遵循原来的设计,设置 application -> 设置 registry -> 设置 protocol -> 设置 serviceConfig 。但在具体实现上跟原来版本也有所区别,比如引入了领域模型进行分层次管理。下一篇文章,我们将分析 Dubbo 3.2 源码 provider 具体的启动流程。