Dubbo 3.x源码(20)—Dubbo服务引用源码(3)

基于Dubbo 3.1,详细介绍了Dubbo服务的发布与引用的源码。

此前我们学习了调用createProxy方法,根据服务引用参数map创建服务接口代理引用对象的整体流程,我们知道会调用createInvokerForRemote方法创建远程引用Invoker,这是Dubbo 3 服务引用的核心方法,我们现在来接着学习createInvokerForRemote方法

Dubbo 3.x服务引用源码:

  1. Dubbo 3.x源码(11)—Dubbo服务的发布与引用的入口
  2. Dubbo 3.x源码(18)—Dubbo服务引用源码(1)
  3. Dubbo 3.x源码(19)—Dubbo服务引用源码(2)
  4. Dubbo 3.x源码(20)—Dubbo服务引用源码(3)

Dubbo 3.x服务发布源码:

  1. Dubbo 3.x源码(11)—Dubbo服务的发布与引用的入口
  2. Dubbo 3.x源码(12)—Dubbo服务发布导出源码(1)
  3. Dubbo 3.x源码(13)—Dubbo服务发布导出源码(2)
  4. Dubbo 3.x源码(14)—Dubbo服务发布导出源码(3)
  5. Dubbo 3.x源码(15)—Dubbo服务发布导出源码(4)
  6. Dubbo 3.x源码(16)—Dubbo服务发布导出源码(5)
  7. Dubbo 3.x源码(17)—Dubbo服务发布导出源码(6)

文章目录

  • 1 createInvokerForRemote创建远程引用Invoker
  • 2 Protocol$Adaptive自适应Protocol
  • 3 ProtocolSerializationWrapper协议序列化包装器
  • 4 ProtocolFilterWrapper协议过滤器包装器
  • 5 ProtocolListenerWrapper协议监听器包装器
  • 6 总结

1 createInvokerForRemote创建远程引用Invoker

远程引用或者直连引用情况下,将会调用该方法,创建远程引用Invoker。该方法对于一个注册中心url和多个注册中心url的处理不一样,我们仅看一个注册中心的情况。

一个注册中心的情况下,该方法主要逻辑就是执行protocolSPI.refer方法,通过协议protocolSPI引用服务Invoker。

这里的protocolSPI是Protocol的自适应扩展实现,即Protocol$Adaptive,将会根据url的协议选择Protocol实现,然后调用Protocol#refer方法引用服务。

我们下面主要看protocolSPI#refer方法方法的相关源码,这也是Dubbo服务引入的核心流程之一。

/*** ReferenceConfig的方法* <p>* 创建远程引用Invoker*/
@SuppressWarnings({"unchecked", "rawtypes"})
private void createInvokerForRemote() {//一个url,表示一个注册中心或者直连地址,这是大多数情况//url例如: registry://47.94.229.245:2181/org.apache.dubbo.registry.RegistryService?REGISTRY_CLUSTER=demo1&application=demo-consumer&dubbo=2.0.2&pid=34457&registry=zookeeper&timeout=20000&timestamp=1666854892012if (urls.size() == 1) {//获取注册中心协议urlURL curUrl = urls.get(0);/** 通过协议protocolSPI引用服务,该方法固定返回InjvmInvoker实例,内部没有NettyClient,因为不需要发起网络调用** 这里的protocolSPI是Protocol的自适应扩展实现,即Protocol$Adaptive* 将会根据url的协议选择Protocol实现,然后调用Protocol#refer方法引用服务*/invoker = protocolSPI.refer(interfaceClass, curUrl);// registry url, mesh-enable and unloadClusterRelated is true, not need Cluster.//如果是registry url(非直连地址), 或者unloadClusterRelated为true,那么不需要Cluster,否则需要Cluster包装//对于远程注册中心协议来说,在protocolSPI.refer方法中就已经进行了Cluster包装,这里不再需要了if (!UrlUtils.isRegistry(curUrl) &&!curUrl.getParameter(UNLOAD_CLUSTER_RELATED, false)) {List<Invoker<?>> invokers = new ArrayList<>();invokers.add(invoker);invoker = Cluster.getCluster(scopeModel, Cluster.DEFAULT).join(new StaticDirectory(curUrl, invokers), true);}}//多个url,表示多个注册中心或者直连地址else {List<Invoker<?>> invokers = new ArrayList<>();URL registryUrl = null;for (URL url : urls) {// For multi-registry scenarios, it is not checked whether each referInvoker is available.// Because this invoker may become available later.invokers.add(protocolSPI.refer(interfaceClass, url));if (UrlUtils.isRegistry(url)) {// use last registry urlregistryUrl = url;}}if (registryUrl != null) {// registry url is available// for multi-subscription scenario, use 'zone-aware' policy by defaultString cluster = registryUrl.getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME);// The invoker wrap sequence would be: ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker// (RegistryDirectory, routing happens here) -> Invokerinvoker = Cluster.getCluster(registryUrl.getScopeModel(), cluster, false).join(new StaticDirectory(registryUrl, invokers), false);} else {// not a registry url, must be direct invoke.if (CollectionUtils.isEmpty(invokers)) {throw new IllegalArgumentException("invokers == null");}URL curUrl = invokers.get(0).getUrl();String cluster = curUrl.getParameter(CLUSTER_KEY, Cluster.DEFAULT);invoker = Cluster.getCluster(scopeModel, cluster).join(new StaticDirectory(curUrl, invokers), true);}}
}

2 Protocol$Adaptive自适应Protocol

Protocol$Adaptive的refer方法将会根据url的协议基于Dubbo SPI机制选择Protocol实现,然后调用Protocol#refer方法引用服务,默认dubbo协议。

/*** Protocol$Adaptive的方法* 基于url协议参数的自适应引用服务** @param arg0 服务class* @param arg1 远程服务的url地址* @return Invoker*/
public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {if (arg1 == null) throw new IllegalArgumentException("url == null");org.apache.dubbo.common.URL url = arg1;//获取url协议作为扩展名,默认dubboString extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());if (extName == null)throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), org.apache.dubbo.rpc.Protocol.class);//基于DUbbo SPI机制查找指定扩展名的Protocol实现类,默认DubboProtocol,这里会进行wrapper包装org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) scopeModel.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);//通过具体的Protocol包装实现类的refer方法实现服务的引用return extension.refer(arg0, arg1);
}

同服务导出时一样,获取Protocol的时候,将会经过wrapper的包装。以InjvmProtocol协议为例,可以看到经过了三层包装,调用时由外向内调用,即ProtocolSerializationWrapper -> ProtocolFilterWrapper -> ProtocolListenerWrapper -> InjvmProtocol(具体的Protocol实现)。实际上Dubbo正式采用warpper机制和装饰设计模式实现类似aop的功能。

本地引入的injvm协议对应InjvmProtocol,需要引入远程接口级注册中心的registry对应InterfaceCompatibleRegistryProtocol,需要引入远程应用级注册中心的service-discovery-registry对应RegistryProtocol。
image.png
下面我们分别讲解这些wrapper和protocol是如何进行服务引入的!

3 ProtocolSerializationWrapper协议序列化包装器

protocol的最外层wrapper,它仅会在导出服务的export方法中起作用,在引入服务的refer方法中没有其他处理。

/*** ProtocolSerializationWrapper的方法*/
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {//无特殊处理return protocol.refer(type, url);
}

4 ProtocolFilterWrapper协议过滤器包装器

这个包装器首先会判断如果是注册中心的协议,例如registry或者service-discovery-registry,那么直接调用下一层refer方法。

否则,获取服务url对应的Filter并且构建为一个InvokerChain对象返回,内部包含了一个下层refer方法的Invoker和一条过滤器调用链。

/*** ProtocolFilterWrapper的方法*/
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {//如果是注册中心的协议,例如registry或者service-discovery-registry,那么直接调用下一层refer方法if (UrlUtils.isRegistry(url)) {return protocol.refer(type, url);}//获取服务url对应的Filter并且构建为一个InvokerChain对象返回,内部包含了一个下层refer方法的Invoker和一条过滤器调用链。FilterChainBuilder builder = getFilterChainBuilder(url);return builder.buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);
}

5 ProtocolListenerWrapper协议监听器包装器

这个包装器首先会判断如果是注册中心的协议,例如registry或者service-discovery-registry,那么直接调用下一层refer方法。

否则,调用下一层refer方法获取返回的Invoker,如果url不包含registry-cluster-type参数,将返回的Invoker包装为ListenerInvokerWrapper,内部包含了一个Invoker和一个监听器列表。

/*** ProtocolListenerWrapper的方法*/
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {//如果是注册中心的协议,例如registry或者service-discovery-registry,那么直接调用下一层refer方法if (UrlUtils.isRegistry(url)) {return protocol.refer(type, url);}//调用下一层refer方法获取返回的InvokerInvoker<T> invoker = protocol.refer(type, url);//如果url不包含registry-cluster-type参数if (StringUtils.isEmpty(url.getParameter(REGISTRY_CLUSTER_TYPE_KEY))) {//将返回的Invoker包装为ListenerInvokerWrapper,内部包含了一个Invoker和一个监听器列表invoker = new ListenerInvokerWrapper<>(invoker,Collections.unmodifiableList(ScopeModelUtil.getExtensionLoader(InvokerListener.class, invoker.getUrl().getScopeModel()).getActivateExtension(url, INVOKER_LISTENER_KEY)));}return invoker;
}

6 总结

本次我们学习了createInvokerForRemote方法中的Wrapper有哪些以及作用,接下来我们将会的学习真正的本地、应用级别、接口级别的Protocol的引入逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/349421.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux文件系统

目录 1.磁盘的结构 1.1磁盘的物理结构 1.2 磁盘的存储结构 1.3 磁盘的逻辑结构 2.文件系统 在上一篇文章基础IO中&#xff0c;我们主要是讲了被打开的文件与进程的关系&#xff0c;以及操作系统是如何管理这些被打开的文件的&#xff0c;但是磁盘有这么多文件&#xff0c;被打…

QT--DAY1

不使用图形化界面实现一个登陆界面 #include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {//设置窗口标题this->setWindowTitle("登录界面");//设置窗口大小this->resize(535,410);//固定窗口大小this->setFixedSize(535,410)…

windows 环境下使用git命令导出差异化文件及目录

一、找出差异化的版本&#xff08;再此使用idea的show history&#xff09; 找到两个提交记录的id 分别为&#xff1a; 二、使用git bash执行命令&#xff08;主要使用 tar命令压缩文件&#xff09; 输出结果&#xff1a;

上心师傅的思路分享(三)--Nacos渗透

目录 1. 前言 2. Nacos 2.1 Nacos介绍 2.2 鹰图语法 2.3 fofa语法 2.3 漏洞列表 未授权API接口漏洞 3 环境搭建 3.1 方式一: 3.2 方式二: 3.3 访问方式 4. 工具监测 5. 漏洞复现 5.1 弱口令 5.2 未授权接口 5.3.1 用户信息 API 5.3.2 集群信息 API 5.3.3 配置…

kubernetes(k8s)集群部署(2)

目录 k8s集群类型 k8s集群规划&#xff1a; 1.基础环境准备&#xff1a; &#xff08;1&#xff09;保证可以连接外网 &#xff08;2&#xff09;关闭禁用防火墙和selinux &#xff08;3&#xff09;同步阿里云服务器时间&#xff08;达到集群之间时间同步&#xff09; &…

pytest并发执行时token异常处理问题

接前面加入钩子函数处理token复用的问题&#xff0c;只保证了用例的串联执行&#xff0c;我的部分测试用例中接入了通义千问的部分接口生成测试数据&#xff0c;七八个场景跑完差不多快要10分钟。考虑使用并发执行。 http://t.csdnimg.cn/ACexL 使用多线程和不使用耗时差距很大…

HyperBDR新版本上线,自动化容灾兼容再升级!

本次HyperBDR v5.5.0版本新增完成HCS&#xff08;Huawei Cloud Stack&#xff09;8.3.x和HCSO&#xff08;Huawei Cloud Stack Online&#xff09;自动化对接&#xff0c;另外还突破性完成了Oracle云(块存储模式)的自动化对接。 HyperBDR&#xff0c;云原生业务级别容灾工具。支…

Unity资源 之 最受欢迎的三消游戏开发包 - Bubble Shooter Kit 【免费领取】

三消游戏开发包 - Bubble Shooter Kit 免费领取 前言资源包内容领取兑换码 前言 如果你是一名 Unity 游戏开发者&#xff0c;并且正在寻找一种快速、简单的方式来创建自己的三消游戏&#xff0c;那么 Bubble Shooter Kit 就是你所需要的。 资源包内容 Bubble Shooter Kit 是…

代码随想录算法训练营第36期 last day

最后一次更新&#xff0c;之后去复习专业课和简历 583两个字符串的删除操作 自己做出来了&#xff1a; Code: class Solution {public://找到公共子序列的最大长度dp 最小步数串1.size-dp串2.size-dp int minDistance(string word1, string word2) { vector<v…

用智能插件(Fitten Code: Faster and Better AI Assistant)再次修改vue3 <script setup>留言板

<template><div><button class"openForm" click"openForm" v-if"!formVisible">编辑</button><button click"closeForm" v-if"formVisible">取消编辑</button><hr /><formv-i…

基于梯度下降的多元线性回归原理

为了展示多元线性回归的迭代过程&#xff0c;我们可以使用梯度下降算法手动实现多元线性回归。梯度下降是一种迭代优化算法&#xff0c;用于最小化损失函数。 我们将以下步骤进行手动实现&#xff1a; 初始化回归系数。计算预测值和损失函数。计算梯度。更新回归系数。重复步…

高分论文密码---大尺度空间模拟预测与数字制图

大尺度空间模拟预测和数字制图技术和不确定性分析广泛应用于高分SCI论文之中&#xff0c;号称高分论文密码。大尺度模拟技术可以从不同时空尺度阐明农业生态环境领域的内在机理和时空变化规律&#xff0c;又可以为复杂的机理过程模型大尺度模拟提供技术基础。我们将结合一些经典…

制造业几大系统(MES/WMS/QMS/ERP)的集成

制造业的几大系统包括MES&#xff08;制造执行系统&#xff09;、WMS&#xff08;仓库管理系统&#xff09;、QMS&#xff08;质量管理系统&#xff09;和ERP&#xff08;企业资源计划&#xff09;系统。这些系统在制造业中扮演着不同的角色&#xff0c;可以通过集成实现更高效…

Kafka高频面试题整理

文章目录 1、什么是Kafka?2、kafka基本概念3、工作流程4、Kafka的数据模型与消息存储机制1)索引文件2)数据文件 5、ACKS 机制6、生产者重试机制:7、kafka是pull还是push8、kafka高性能高吞吐的原因1&#xff09;磁盘顺序读写&#xff1a;保证了消息的堆积2&#xff09;零拷贝机…

SqlSugar有实体CURD应用-C#

本文所述开发环境&#xff1a;.C#、NET8、Visual Studio2022 SqlSugar有实体查询数据表 首先根据《SqlSugar使用DbFirst对象根据数据库表结构创建实体类-C#》中的描述的表结构创建所有表的实体类如下&#xff1a; 表名创建的实体类名tb_studentStudenttb_teacherTeachertb_c…

linux的UDP广播测试:C语言代码

测试代码 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h>#…

MyEclipse新手使用介绍

目录 1.MyEclipse诞生背景 2.作用 3.版本历史 4.优缺点 5.应用场景 6.如何使用 6.1.下载与安装 6.2.MyEclipse 菜单及其菜单项 7.创建和发布一个 Java 程序 7.1.创建 Java 程序 7.2.发布 Java 程序 8.示例 8.1. Hello World 示例 8.2. 简单Spring Boot 应用 8.3…

kettle从入门到精通 第六十九课 ETL之kettle kettle cdc mysql,轻松实现增量同步

1、之前kettle cdc mysql的时候使用的方案是canalkafkakettle&#xff0c;今天我们一起学习下使用kettle的插件Debezium直接cdc mysql。 注&#xff1a;CDC (Change Data Capture) 是一种技术&#xff0c;用于捕获和同步数据库中的更改。 1&#xff09;Debezium步骤解析mysql b…

鸿蒙轻内核Kconfig使用笔记

鸿蒙轻内核使用Kconfig进行图形化配置&#xff0c;本文专门讲解下鸿蒙轻内核LiteOS-M和LiteOS-A的图形化配置方法。本文中所涉及的源码&#xff0c;均可以在开源站点 https://gitee.com/openharmony/kernel_liteos_a 、 https://gitee.com/openharmony/kernel_liteos_m 获取。本…

Spring AI 接入OpenAI实现文字生成图片功能

Spring AI 框架集成的图片大模型 2022年出现的三款文生图的现象级产品&#xff0c;DALL-E、Stable Diffusion、Midjourney。 OpenAI dall-e-3dall-e-2 Auzre OpenAI dall-e-3dall-e-2 Stability stable-diffusion-v1-6 ZhiPuAI cogview-3 OpenAI 与 Auzer OpenAI 使用的图片…