一直以来对Dubbo的实现原理颇为好奇,前几个月在Dubbo专栏里也陆续写了几遍文章,奈何自身原因+客观原因,就没有坚持下来。这次重启Dubbo源码刨析系列,也刚好可以借着2023年7月发布的比较新的Dubbo 3.2版本源码进行学习研究,共勉!
这里我们还是以provider启动的Demo为入口,进行分析:
public interface DemoService {
String sayHello(String name);
}
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();
}
}
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()
根据官网的文档描述,Dubbo3中引入“模型的概念”来进行服务级别的管理工作,像配置中心和元数据中心的管理。而这么做的原因,也有着对应的解释:
- 让Dubbo支持多应用的部署,这块一些大企业有诉求
- 从架构设计上,解决静态属性资源共享、清理的问题
- 分层模型将应用的管理和服务的管理分开
public final <T extends AbstractConfig> T addConfig(AbstractConfig config) {
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<String, AbstractConfig> configsMap =
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);
}
}
public DubboBootstrap registry(RegistryConfig registryConfig) {
registryConfig.setScopeModel(applicationModel);
configManager.addRegistry(registryConfig);
return this;
}
图1
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
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 具体的启动流程。