全国旗舰校区

不同学习城市 同样授课品质

北京

深圳

上海

广州

郑州

大连

武汉

成都

西安

杭州

青岛

重庆

长沙

哈尔滨

南京

太原

沈阳

合肥

贵阳

济南

下一个校区
就在你家门口
+
当前位置:首页  >  技术干货

dubbo源码解析-服务暴露与发现

发布时间:2023-03-31 11:03:00
发布人:syq

  Dubbo是一款高性能、轻量级的分布式服务框架,其中服务暴露与发现是其核心功能之一。在本篇文章中,我们将介绍Dubbo在服务暴露和发现方面的实现原理。

dubbo源码解析-服务暴露与发现

  服务暴露

  服务暴露的过程是将服务接口以及实现类发布到注册中心,以便其他应用程序可以发现并进行调用。Dubbo的服务暴露过程通常涉及到以下几个步骤:

  创建服务接口代理对象:Dubbo使用Java Proxy机制为服务接口创建代理对象。

  封装服务暴露信息:将服务的接口名称、版本号、实现类、调用协议、序列化方式等信息封装到URL对象中,并通过Dubbo SPI机制获取相应的协议实现。

  启动协议服务:将封装好的URL对象传递给协议实现并启动服务器,协议实现负责监听端口并接收来自其他应用程序的调用请求。

  将服务暴露到注册中心:将服务暴露所需的信息注册到注册中心,供其他应用程序查找和调用。

  以下是服务暴露的核心代码片段:

public void export() {
// 1. 创建服务代理对象
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryUrl.addParameterAndEncoded(REFER_KEY, URL.encode(url.toFullString())));

// 2. 创建URL,并将服务暴露信息封装到URL中
URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryUrl);
if (monitorUrl != null) {
url = url.addParameterIfAbsent(MONITOR_KEY, monitorUrl.toString());
}
// 将服务的接口名称、版本号、实现类、调用协议、序列化方式等信息封装到URL对象中
Map<String, String> map = new HashMap<String, String>();
map.put(SIDE_KEY, PROVIDER_SIDE);
appendRuntimeParameters(map);
// 添加服务协议配置
appendProtocolParameters(map);
// 添加服务元数据配置
appendParameters(map, getMetrics());
// 封装服务暴露信息到URL中
if (CollectionUtils.isNotEmpty(getMethods())) {
for (MethodConfig methodConfig : getMethods()) {
appendParameters(map, methodConfig, methodConfig.getName());
}
}
// 将URL参数封装到URL中
url = url.addParameters(map)
.addParameterAndEncoded(EXPORT_KEY, invoker.getUrl().toFullString());
if (StringUtils.isNotEmpty(token)) {
if (ConfigUtils.isDefault(token)) {
token = UUID.randomUUID().toString();
}
url = url.addParameter(TOKEN_KEY, token);
}

// 3. 启动协议服务
String scope = url.getParameter(SCOPE_KEY);
// 通过SPI机制获取协议实现
Protocol protocol = extensionLoader.getExtension(scope != null && scope.length() > 0 ? scope : getDefaultProtocol()).getAdaptiveProtocol();
// 启动协议服务
exporter = protocol.export(invoker);

// 4. 将服务暴露到注册中心
// 获取注册中心实现
Registry registry = registryFactory.getRegistry(registryUrl);
// 注册服务
registry.register(getRegisterUrl());
}

 

  服务发现

  在Dubbo中,服务发现是用来查找远程服务的过程。它通过从注册中心查找已注册的服务,获得该服务的地址列表,进而构建服务代理对象,以便进行调用。Dubbo服务发现的流程通常可以分为以下几个步骤:

  解析服务URL:Dubbo将服务URL解析为接口名称、版本号以及协议等相关信息。

  获取注册中心:Dubbo通过配置文件获取注册中心的地址,并通过Dubbo SPI机制获取相应的注册中心实现。

  从注册中心获取服务地址列表:Dubbo通过注册中心获取服务的地址列表,并对地址列表进行缓存处理,以避免频繁的网络调用。

  构建服务代理对象:Dubbo使用Java Proxy机制为服务接口创建代理对象,并通过封装好的地址列表构造Invoker对象。

  调用远程服务:Dubbo将调用请求发送到远程服务,获取调用结果并将其返回给调用方。

  以下是服务发现的核心代码片段:

public  T refer(Class type, URL url) throws RpcException {
// 解析出接口名称、版本号以及协议等相关信息
url = URLBuilder.from(url)
.setProtocol(Constants.REGISTRY_PROTOCOL) // 设置协议为注册中心协议
.addParameterAndEncoded(REFER_KEY, url.toFullString()) // 添加引用配置
.build();

// 获取注册中心对象
Registry registry = registryFactory.getRegistry(url);
// 获取服务代理对象
if (RegistryService.class.equals(type)) {
return proxyFactory.getProxy(invokerFactory.getInvoker(registry, type, url));
}

// 将调用的服务接口名称和版本号封装到URL中
Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));
String group = qs.get(Constants.GROUP_KEY);
String version = qs.get(Constants.VERSION_KEY);
if (group != null && group.length() > 0) {
url = url.addParameter(Constants.GROUP_KEY, group);
}
if (version != null && version.length() > 0) {
url = url.addParameter(Constants.VERSION_KEY, version);
}

// 从缓存中获取服务地址列表
String key = url.toServiceString();
ReferenceConfigCache cache = ReferenceConfigCache.getCache();
T ref = (T) cache.get(key);
if (ref == null) {
// 获取服务地址列表
List urls = new ArrayList();
// 参数省略...
if (urls == null || urls.isEmpty()) {
throw new RpcException("No provider available for the service "
+ type.getName() + " from registry " + url.getRegistryAddress()
+ " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
+ Version.getVersion() + ". Please check if the providers have been started and registered.");
}
// 构建服务代理对象
List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
for (URL u : urls) {
invokers.add(proxyFactory.getInvoker((T) type, u));
}
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invokers.get(0), type, urls.get(0));
ref = proxyFactory.getProxy(wrapperInvoker);
cache.put(key, ref);
}
return ref;
}

 

  总结

  服务暴露与发现是Dubbo的核心功能之一,也是基于Dubbo构建其他应用程序的核心能力。在服务暴露的过程中,Dubbo需要将服务信息封装到URL中,并通过SPI机制获取相应的协议实现,启动协议服务,并将服务信息注册到注册中心中。而在服务发现的过程中,Dubbo需要通过解析服务URL获取相关信息,获取注册中心实例,从注册中心获取服务地址列表,构建服务代理对象并进行调用。掌握Dubbo的服务暴露与发现过程,有助于我们更加深入理解Dubbo的实现原理。

相关文章

python写入json文件?

python写入json文件?

2023-11-02
vscode设置tab为4个空格?

vscode设置tab为4个空格?

2023-11-02
更新pycharm?

更新pycharm?

2023-11-02
anaconda每次打开都要安装?

anaconda每次打开都要安装?

2023-11-02

最新文章

武汉新媒体行业公司排名

武汉新媒体行业公司排名

2023-11-01
武汉新媒体就业现状好吗

武汉新媒体就业现状好吗

2023-11-01
武汉全媒体行业发展现状及趋势

武汉全媒体行业发展现状及趋势

2023-10-31
武汉全媒体现状

武汉全媒体现状

2023-10-31
在线咨询 免费试学 教程领取