Dubbo消费端源码深入分析(8)

news2024/11/28 5:31:27

目录

简介

过滤器 (Filter)

负载均衡接口 (LoadBalance)

容错接口 (Cluster)

源码分析

1. 获取Invoker过程

2. 获取动态代理对象proxy

3. 最后调用此动态代理对象的invoke方法

过滤器、容错组件、负载均衡之间的关系


简介

本篇将围绕Dubbo消费端的主流程进行讲解,其中会涉及到过滤器、容错、复杂均衡进行重点分析。

首先,我们需要认识几个重要的接口 Filter、Cluster、LoadBalance,分别对应过滤器、容错、复杂均衡。下面会这几个接口进行初步介绍。

过滤器 (Filter)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.extension.SPI;

@SPI
public interface Filter {
    Result invoke(Invoker<?> var1, Invocation var2) throws RpcException;
}

一看就是Dubbo SPI的设计思想,实现类如下:

而他的配置文件如下:

负载均衡接口 (LoadBalance)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.alibaba.dubbo.rpc.cluster;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.SPI;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
import java.util.List;

@SPI("random")
public interface LoadBalance {
    @Adaptive({"loadbalance"})
    <T> Invoker<T> select(List<Invoker<T>> var1, URL var2, Invocation var3) throws RpcException;
}

默认策略是随机策略,而他的实现类和对应的key为:

容错接口 (Cluster)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.alibaba.dubbo.rpc.cluster;

import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.SPI;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;

@SPI("failover")
public interface Cluster {
    @Adaptive
    <T> Invoker<T> join(Directory<T> var1) throws RpcException;
}

对应的实现类,以及key-value结构如下:

源码分析

客户端测试代码:

   @Test
    public void clientRpc() throws IOException
    {
        Protocol protocol = protocolLoader.getAdaptiveExtension();
        //代理
        ProxyFactory proxy = proxyLoader.getAdaptiveExtension();
        //消费服务
        Invoker<DemoService> referInvoker = protocol.refer(DemoService.class, registryUrl);
        DemoService service = proxy.getProxy(referInvoker);

        for (int i = 0;i < 5;i++){
            String result = service.sayHello(registryUrl.getProtocol()+"调用");
            System.out.println(result);
        }
        // 保证服务一直开着
//        System.in.read();

    }

1. 获取Invoker过程

我们知道,无论是 ProxyFactory 还是 Protocol, 他两都是一个静态代理类,那么获取Invoker对象实际调用到的就是静态代理类的refer方法:

进入到RegistryProtocol类的getInvoker方法。其实,就是根据注册中心的registryURL和 Interface信息到注册中心中进行注册与订阅操作。我们使用的是zookeeper,那也就是zookeeper的发布与定于操作,不是本文的重点,在分析zookeeper的时候会重点分析。

 其实,我们获取的Invoker对象,是一个容错对象 invoker

2. 获取动态代理对象proxy

 

因为proxy是一个静态代理对象,因此会调用此对象的getProxy方法

 

3. 最后调用此动态代理对象的invoke方法

随着debug的深入,我们发现它首先调用的是容错组件的子类:

而在容错组件的深入过程中,我们发现在容错组件的调用过程中,我们又调用到了负载均衡的策略:

 最后继续走到方法的最后一行,又调用了doInvoke方法。其实,这就是负载均衡的详细逻辑

继续debug,我们发现它进入了 ProtocolFilterWrapper 内部,并且调用了invoke方法。而当前方法很明显是一个链式调用。

 继续debug,我发现他们调用调用了很多的过滤器Filter的实现类,其中就有我们自己定义的过滤器实现类。最后,它才会调用到实际的动态代理对象的invoke方法,进行网络调用:

我们发现,它正常调用到了服务端的信息,并且返回预期的结果。

过滤器、容错组件、负载均衡之间的关系

1.  其实,普通的RPC调用,完全可以理解成Invoker对象的直接调用。 也就是服务端直接把要暴露的服务封装成 Invoker对象进行暴露,消费端直接根据URL进行调用,这是最简单、最原始的调用

    消费端 Invoker.invoke ------> 网络 ---> 服务端 Invoker.invoker ----> 实际暴露的业务

2. Dubbo可以看做是对RPC进行了增强

消费端 invoker.invoke ------>容错策略--->网络---->服务端 invoker.invoke--->ref 服务
 

为了统一接口,dubbo对外暴露的就是一个Invoker接口而已,而Invoker嵌套Invoker就是一个不错的设计,改造完成后:

FailfastClusterInvoker.invoke--->protocolInvoker.invoke-->网络---->服务端
invoker.invoke--->ref 服务


依次类推, dubbo 内部有非常多的 invoker 包装类, 它们层层嵌套, 但 rpc
流程不关心细节, 只傻瓜式地调用其 invoke 方法, 剩下的逻辑自会传递到
最后一个 invoker 进行网络调用。

3.    针对Dubbo系统默认的策略,我发现是的  容错 Invoker ------> 嵌套  负载均衡Invoker  -----> 嵌套 网络协议Invoker  ---->  过滤器Invoker  ----> 最原始的 Invoker。

 4.  其实,容错、负载均衡、过滤器都可以单独使用。

      而如何搭配使用的话,容错invoker 内部嵌套 负载均衡的invoker;

      没有负载均衡的话,那就是 容错invoker 内部嵌套 过滤器的invoker;

全部使用的话 容错invoker 内部嵌套 负载均衡的invoker  内部再嵌套 过滤器的invoker;

5. 过滤器是一个链式调用关系,会逐个调用

其实,这只是目前发现的一种微妙关系,并不代表就一定是这样的。如有错误,请多指正

Dubbo这种玩意,真正的威力是扩展功能。 而扩展是基于Dubbo SPI思想得以实现的。如果有人问我阅读Dubbo源码最大的收益是什么,我的回答一定是Dubbo SPI设计思想。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基础IO(二)

磁盘 1.基础概念2.磁盘线性理解3.文件系统4.inode与文件名5.理解增删查改6.补充细节 &#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f;&#x1f31f; &#x1f680;&#x1f680;系列专栏&#xff1a;【Linux的学习】 &#x1f4dd;&#x1f4…

Chapter7:非线性控制系统分析(下)

第七章:非线性控制系统分析 Exercise7.11 设非线性系统结构图如下图所示,分析系统运动并计算自振参数。 解: 将 3 3 3个串联非线性环节进行等效合并,由于反馈通道饱和特性与前向通道饱和特性同时进入饱和状态,所以反馈通道的非线性环节相当于不起作用,将前向通道的另两…

【计算机视觉 | 自然语言处理】Hugging Face 超详细介绍和使用教程

文章目录 一、前言二、可以获得什么&#xff1f;三、入门实践3.1 帮助文档3.2 安装3.3 模型的组成3.4 BERT模型的使用3.4.1 导入模型3.4.2 使用模型3.4.2.1 tokenizer 3.5 model3.6 后处理 一、前言 Hugging Face 起初是一家总部位于纽约的聊天机器人初创服务商&#xff0c;他…

URP渲染管线里面的摄像机用法

大家好&#xff0c;我是阿赵&#xff0c;这里继续讲一下URP渲染管线。 这次要讲的是URP渲染管线里面的摄像机用法 之前介绍过&#xff0c;URP摄像机和普通摄像机的属性显示上有比较大的变化&#xff1a; 接下来从用法上来说明一下&#xff1a; 1、多个摄像机的处理变化 多个…

unity UGUI系统梳理 -交互组件

概述 unity 中的交互组件可用于处理交互&#xff0c;例如鼠标或触摸事件以及使用键盘或控制器进行的交互 1、按钮 (Button) Button详解 2、开关 (Toggle) Background&#xff1a;背景图片&#xff0c;控制toggle组件的背景颜色改变&#xff0c;从而展示此物体是否被选中的…

5.View的事件分发机制/事件处理机制原理分析

事件MotionEvent包含了哪几个? ACTION_DOWN 手指触碰到屏幕时触发,只会执行一次ACTION_MOVE 手指在屏幕上滑动出发,会执行多次ACTION_UP 手指抬起离开屏幕出发,只会执行一次ACTION_CANCEL 事件被上层拦截时会触发 父容器ViewGroup需要从子View手中抢夺分发的事件进行处理时,会…

【SCI】综合能源系统中热电联产、电制气和碳捕集系统的建模与优化(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Java 网络编程 —— 非阻塞式编程

线程阻塞概述 在生活中&#xff0c;最常见的阻塞现象是公路上汽车的堵塞。汽车在公路上快速行驶&#xff0c;如果前方交通受阻&#xff0c;就只好停下来等待&#xff0c;等到公路顺畅&#xff0c;才能恢复行驶。 线程在运行中也会因为某些原因而阻塞。所有处于阻塞状态的线程…

C++数据结构:哈希 -- unordered系列容器、哈希表的结构以及如何通过闭散列的方法解决哈希冲突

目录 一. unordered系列关联式容器 1.1 unrodered_map和unordered_set 综述 1.2 常见的接口函数&#xff08;以unordered_map为例&#xff09; 1.3 unordered系列与map和set的效率对比 二. 哈希表的底层结构 2.1 什么是哈希 2.2 哈希函数 2.3 哈希冲突 三. 通过闭散列的…

JavaEE(系列2) -- 多线程(创建多线程)

讲述下面的内容之前,先来回顾一下一个重要的知识点 进程和线程之间的区别 1.进程包括线程。 2.进程有自己独立的内存空间和文件描述符表。同一个进程中的多个线程之间&#xff0c;共享同一份地址空间和文件描述符表。 3.进程是操作系统资源分配的基本单位&#xff0c;线程是操作…

5.14学习周报

文章目录 前言文献阅读摘要介绍方法模型框架评价指标结果结论 时间序列预测总结 前言 本周阅读文献《A Hybrid Model for Water Quality Prediction Based on an Artificial Neural Network, Wavelet Transform, and Long Short-Term Memory》&#xff0c;文献主要提出了基于人…

iconfont-extract: 一个将iconfont图标转化为React组件的工具

iconfont 提供了海量的图标&#xff0c;同时也方便了前端开发者使用这些图标&#xff0c;只需要添加对应的js、css或者字体文件即可。在我们的项目中使用添加js文件的方式&#xff0c;js文件中都包含了所有的图标&#xff0c;一个项目中通常只会使用其中的一部分&#xff0c;所…

【架构设计】DDD 到底解决了什么问题

文章目录 前言一、架构设计是为了解决系统复杂度1.1 架构设计的误区1.1.1 每个系统都要做架构设计/公司流程要求有架构设计1.1.2 架构设计是为了追求高性能、高可用、可扩展性等单一目标 1.2 架构设计的真正目的1.3 系统复杂度的六个来源及通用解法1.3.1 高性能1.3.1.1 单机复杂…

JavaWeb-一篇文章带你入门CSS(笔记+案列)

目录 CSS是什么基本语法 CSS的引入方式内部样式表行内样式表外部样式表 选择器基础选择器标签选择器类选择器id选择器通配符选择器 复合选择器后代选择器子选择器 常用元素属性字体属性文本属性背景属性圆角矩形 元素的显示模式块级元素行内元素 我们可以使用display属性来修改…

对称加密/非对称加密

古典密码学 起源于古代战争:在战争中&#xff0c;为了防止书信被截获后重要信息泄露&#xff0c;人们开始对书信进行加密。 移位式加密 如密码棒&#xff0c;使用布条缠绕在木棒上的方式来对书信进行加密。 加密算法&#xff1a;缠绕后书写 密钥&#xff1a; 木棒的尺寸 替…

[笔记]深入解析Windows操作系统《四》管理机制

文章目录 前言4.1注册表查看和修改注册表注册表用法注册表数据类型注册表逻辑结构HKEY_CURRENT_USERHKEY_USERS 实验&#xff1a;观察轮廓加载和卸载HKEY_CLASSES_ROOTHKEY_LOCAL_MACHINE 实验:离线方式或远程编辑BCDHKEY_CURRENT_CONFIGHKEY_PERFORMANCE_DATA 前言 本章讲述了…

day3_垃圾回收器

文章目录 Serial回收器ParNew回收器Parallel Scavenge回收器Serial Old回收器Parallel Old回收器CMS&#xff08;Concurrent Mark Sweeping)回收器G1 主要有7种垃圾回收器&#xff0c;如下所示&#xff1a; 其中有直线关联的表示&#xff0c;这2种垃圾回收器可以配合使用的。 S…

大模型之PaLM2简介

1 缘起 大模型时代。 时刻关注大模型相关的研究与进展&#xff0c; 以及科技巨头的商业化大模型产品。 作为产品&技术普及类文章&#xff0c;本文将围绕PaLM2是什么、特点、如何使用展开。 想要了解更多信息的可以移步官方网站提供的参考文档&#xff0c;后文会给出相关链…

Oracle11g服务说明

一、服务说明 1.OracleDBConsoleorcl&#xff1a;非必须启动 Oracle数据库控制台服务&#xff0c;orcl是Oracle的实例标识&#xff0c;默认的实例为orcl。在运行Enterprise Manager&#xff08;企业管理器OEM&#xff09;的时候&#xff0c;需要启动这个服务。 2.OracleJobS…

一文了解异步编程

promise 什么是promise promise是异步编程的一种解决方案&#xff0c;从语法上来说&#xff0c;Promise是一个对象&#xff0c;从它可以获取异步操作的消息 ES6规定&#xff0c;Promise对象是一个构造函数&#xff0c;接受一个函数作为参数&#xff0c;这个函数会立即执行&a…