dubbo 3.2.0 merge模式及 adaptive class 生成过程

news2024/9/21 8:00:51

MergeInvoker生成过程分析

dubbo 3.2.0 merge模式是汇聚多个group内相同服务的返回,核心MergeInvoker代码在public class RegistryDirectory extends DynamicDirectory 内的如下函数。

private List<Invoker<T>> toMergeInvokerList(List<Invoker<T>> invokers) {
    List<Invoker<T>> mergedInvokers = new ArrayList<>();
    Map<String, List<Invoker<T>>> groupMap = new HashMap<>();
    for (Invoker<T> invoker : invokers) {
        String group = invoker.getUrl().getGroup("");
        groupMap.computeIfAbsent(group, k -> new ArrayList<>());
        groupMap.get(group).add(invoker);
    }

    if (groupMap.size() == 1) {
        mergedInvokers.addAll(groupMap.values().iterator().next());
    } else if (groupMap.size() > 1) {
        for (List<Invoker<T>> groupList : groupMap.values()) {
            StaticDirectory<T> staticDirectory = new StaticDirectory<>(groupList);
            staticDirectory.buildRouterChain();
            mergedInvokers.add(cluster.join(staticDirectory, false));
        }
    } else {
        mergedInvokers = invokers;
    }
    return mergedInvokers;
}

如果进行dubug,会发现这段代码
mergedInvokers.add(cluster.join(staticDirectory, false));
无法跟踪,原因cluster是通过JavassistCompiler类编译生成的adaptive 类。

这个cluster的类是基于
@SPI("failover")
public interface Cluster {
    String DEFAULT = "failover";

    @Adaptive
    <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException;

    static Cluster getCluster(ScopeModel scopeModel, String name) {
        return getCluster(scopeModel, name, true);
    }

    static Cluster getCluster(ScopeModel scopeModel, String name, boolean wrap) {
        if (StringUtils.isEmpty(name)) {
            name = "failover";
        }

        return (Cluster)ScopeModelUtil.getApplicationModel(scopeModel).getExtensionLoader(Cluster.class).getExtension(name, wrap);
    }
}

来生成,注意下这里的DEFAULT ,决定了实际invoker。

类里面的method,是有public class AdaptiveClassCodeGenerator 的

/**
 * generate method content
 */
private String generateMethodContent(Method method) {
    Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
    StringBuilder code = new StringBuilder(512);
    if (adaptiveAnnotation == null) {
        return generateUnsupported(method);
    } else {
        int urlTypeIndex = getUrlTypeIndex(method);

        // found parameter in URL type
        if (urlTypeIndex != -1) {
            // Null Point check
            code.append(generateUrlNullCheck(urlTypeIndex));
        } else {
            // did not find parameter in URL type
            code.append(generateUrlAssignmentIndirectly(method));
        }

        String[] value = getMethodAdaptiveValue(adaptiveAnnotation);

        boolean hasInvocation = hasInvocationArgument(method);

        code.append(generateInvocationArgumentNullCheck(method));

        code.append(generateExtNameAssignment(value, hasInvocation));
        // check extName == null?
        code.append(generateExtNameNullCheck(value));

        code.append(generateScopeModelAssignment());
        code.append(generateExtensionAssignment());

        // return statement
        code.append(generateReturnAndInvocation(method));
    }

    return code.toString();
}

来生成,其实就只有一个join方法,实际生成的类如下:

package org.apache.dubbo.rpc.cluster;

import org.apache.dubbo.rpc.model.ScopeModel;
import org.apache.dubbo.rpc.model.ScopeModelUtil;

public class Cluster$Adaptive implements org.apache.dubbo.rpc.cluster.Cluster {
    public org.apache.dubbo.rpc.Invoker join(org.apache.dubbo.rpc.cluster.Directory arg0, boolean arg1) throws org.apache.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.cluster.Directory argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("org.apache.dubbo.rpc.cluster.Directory argument getUrl() == null");
        org.apache.dubbo.common.URL url = arg0.getUrl();
        String extName = url.getParameter("cluster", "failover");
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.cluster.Cluster) name from url (" + url.toString() + ") use keys([cluster])");
        ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), org.apache.dubbo.rpc.cluster.Cluster.class);
        org.apache.dubbo.rpc.cluster.Cluster extension = (org.apache.dubbo.rpc.cluster.Cluster) scopeModel.getExtensionLoader(org.apache.dubbo.rpc.cluster.Cluster.class).getExtension(extName);
        return extension.join(arg0, arg1);
    }

    public org.apache.dubbo.rpc.cluster.Cluster getCluster(org.apache.dubbo.rpc.model.ScopeModel arg0, java.lang.String arg1) {
        throw new UnsupportedOperationException("The method public static org.apache.dubbo.rpc.cluster.Cluster org.apache.dubbo.rpc.cluster.Cluster.getCluster(org.apache.dubbo.rpc.model.ScopeModel,java.lang.String) of interface org.apache.dubbo.rpc.cluster.Cluster is not adaptive method!");
    }

    public org.apache.dubbo.rpc.cluster.Cluster getCluster(org.apache.dubbo.rpc.model.ScopeModel arg0, java.lang.String arg1, boolean arg2) {
        throw new UnsupportedOperationException("The method public static org.apache.dubbo.rpc.cluster.Cluster org.apache.dubbo.rpc.cluster.Cluster.getCluster(org.apache.dubbo.rpc.model.ScopeModel,java.lang.String,boolean) of interface org.apache.dubbo.rpc.cluster.Cluster is not adaptive method!");
    }

}

把这个类放到Project,就可以进行debug,debug就会发现一个奇怪的类:MOCKcluster被引用,然后才是FailoverCluster

doJoin:33, FailoverCluster (org.apache.dubbo.rpc.cluster.support)
join:59, AbstractCluster (org.apache.dubbo.rpc.cluster.support.wrapper)
join:39, MockClusterWrapper (org.apache.dubbo.rpc.cluster.support.wrapper)
join:40, ScopeClusterWrapper (org.apache.dubbo.rpc.cluster.support.wrapper)
join:17, Cluster$Adaptive (org.apache.dubbo.rpc.cluster)
toMergeInvokerList:337, RegistryDirectory (org.apache.dubbo.registry.integration)
refreshInvoker:298, RegistryDirectory (org.apache.dubbo.registry.integration)

最后生成的mergedInvokers 信息如下:
在这里插入图片描述

可以通过cluster指定模式,比如改为failback,也就是merge是按设置调用相关group对应的service,但每个group内如何调用是通过cluster及balance控制。

@DubboReference(group = "*",merger = "true",cluster = "failback")
MergeService mergeService;

具体的cluster 类型在org.apache.dubbo.rpc.cluster.Cluster
在这里插入图片描述
内定义,文件内容如下:

mock=org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper
scope=org.apache.dubbo.rpc.cluster.support.wrapper.ScopeClusterWrapper
failover=org.apache.dubbo.rpc.cluster.support.FailoverCluster
failfast=org.apache.dubbo.rpc.cluster.support.FailfastCluster
failsafe=org.apache.dubbo.rpc.cluster.support.FailsafeCluster
failback=org.apache.dubbo.rpc.cluster.support.FailbackCluster
forking=org.apache.dubbo.rpc.cluster.support.ForkingCluster
available=org.apache.dubbo.rpc.cluster.support.AvailableCluster
mergeable=org.apache.dubbo.rpc.cluster.support.MergeableCluster
broadcast=org.apache.dubbo.rpc.cluster.support.BroadcastCluster
zone-aware=org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster

PS:
1、cluster模式可以通过SPI增加
2、可以自己定义merger方法

在这里插入图片描述

其它merger参考url:

https://www.jianshu.com/p/512e2211f84c
https://blog.csdn.net/qq_36882793/article/details/117366243
https://cn.dubbo.apache.org/en/docs/v2.7/user/examples/group-merger/
https://cn.dubbo.apache.org/en/docs3-v2/java-sdk/reference-manual/spi/description/merger/

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

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

相关文章

Spring整合Mybatis框架开发步骤分析

文章目录 1.导入坐标2.配置SpringConfig类3.配置jdbc配置类4.配置MybatisConfig配置类5. xml配置与注解配置之间的转换对比 1.导入坐标 先将依赖坐标导入pom文件中、里面包括spring-context、druid、mybatis、mysql-connector-java、 spring开放出接口标准&#xff0c;如想和…

Redis6 数据结构Hash

前言 在Redis中&#xff0c;hashtable 被称为字典&#xff08;dictionary&#xff09;,它是一个数组链表到结构。每个键值对都会有一个dictEntry OBJ_ENCODING_HT 这种编码夯实内部才是真正的哈希表结构&#xff0c;或称为字典结构&#xff0c;其可以实现O(1)复杂度的读写操作…

深度学习进阶篇[7]:Transformer模型长输入序列、广义注意力、FAVOR+快速注意力、蛋白质序列建模实操。

【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍&#xff1a;【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化…

MP3 Module 语音播放模块(Arduino和串口控制)

MP3 Module 语音播放模块&#xff08;Arduino和串口控制&#xff09; 前言电气参数原理图MP3文件所放位置和命名规则&#xff1a;接线代码串口控制通讯指令&#xff08;部分&#xff09;实验结果 前言 Emakefun MP3语音模块内置8 MB存储空间&#xff0c;无需外接SD卡&#xff…

acwing提高——迭代加深+双向dfs+IDA*

1.迭代加深 顾名思义说明迭代的层数逐渐加深&#xff0c;这样做法有点像bfs的做法层层突出&#xff0c;符合的题型是答案在层数较低的那一层里 加成序列 题目https://www.acwing.com/problem/content/description/172/ #include<bits/stdc.h> using namespace std; c…

接口测试系列之 —— 前端交互测试和后端逻辑测试

01 前端交互测试 前端页面与后端代码之间的交互测试&#xff0c;可以理解为接口功能测试的一个子集。 测试准备 在进行交互测试前&#xff0c;首先要对前端功能有明确的认知&#xff0c;能够明确区分&#xff1a; 什么功能属于前端页面逻辑功能 什么功能又属于前端与后端…

路径规划算法:基于树种优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于树种优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于树种优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法树种…

JMeter快速入门指南:轻松掌握基本操作

Jmeter 介绍 Jmeter 是一款使用Java开发的&#xff0c;开源免费的&#xff0c;测试工具&#xff0c; 主要用来做功能测试和性能测试&#xff08;压力测试/负载测试&#xff09;. 而且用Jmeter 来测试 Restful API, 非常好用。 2023Jmeter性能测试项目实战教程&#xff0c;十…

ffmpeg下载及ffmpy3安装使用

ffmpeg下载及ffmpy3安装使用 1.下载ffmpeg 进入网址&#xff1a;https://www.gyan.dev/ffmpeg/builds/ 在release builds中下载ffmpeg-release-full.7z 下载好后解压到自己想存放的目录&#xff0c;例如&#xff1a;D:\Tool\ffmpeg-6.0-full_build 2.配置环境变量 右键此电…

《最新出炉》Python+Playwright自动化测试-1-环境准备与搭建

一.简介 有很多人问能不能介绍一下Playwright这款自动化神器的相关知识&#xff0c;现在网上的资料太少了。其实在各大博客和公众号也看到过其相关的介绍和讲解。要不就是不全面、不系统&#xff0c;要不就是系统全面但是人家是收费的。当然了接下来也可能介绍的不全面或者不系…

什么是压力测试?什么是负载测试?这两个区别是什么?

前言 之前给一个客户做项目时&#xff0c;由于自己对性能测试了解并不深&#xff0c;搞不懂压力测试和负载测试的区别&#xff0c;导致后面还是由负责性能测试的同事来处理&#xff0c;他跟我说了很多关于压力测试和负载测试的区别&#xff0c;现在我总结如下。 压力测试 压…

解决node上传文件乱码问题终极方案

问题描述 今天在菜鸟教程学习node上传文件时遇到了一个中文乱码的问题&#xff0c;文件名包含中文就会显示乱码&#xff0c;上传到服务器的文件名也是乱码。试了两个方法都不行&#xff0c;最后还是问了万能的度娘才解决。 我做了一个非常简单的上传文件的界面&#xff0c; …

Java SE(十二)之多线程

文章目录 概述1.进程&线程2.并行&并发 线程创建方式1.第一种&#xff1a;继承Thread类2.第二种&#xff1a;实现Runnable接口3.Callable、FutureTask接口4.线程创建的三种方式对比 Thread常用方法1.构造器2.设置和获取线程名称3.线程调度4.线程控制5.线程生命周期 线程…

静态路由和默认路由的工作原理

目录 静态路由 静态路由配置 默认&#xff08;缺省&#xff09;路由 路由的高级特性 1&#xff0c;递归路由 2&#xff0c;等价路由 3&#xff0c;浮动路由 4&#xff0c;路由汇总 环路问题&#xff1a; 解决方法&#xff1a; 静态路由 在路由器手动添加路由条目 静…

基于深度学习的高精度浣熊检测识别系统(PyTorch+Pyside6+模型)

摘要&#xff1a;基于深度学习的高精度浣熊检测&#xff08;水牛、犀牛、斑马和大象&#xff09;识别系统可用于日常生活中或野外来检测与定位浣熊目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的浣熊目标检测识别&#xff0c;另外支持结果可视化与图片或视…

Spring Boot 集成支付宝、微信等支付平台API

Spring Boot 集成支付宝、微信等支付平台API 在现代的 Web 应用程序开发中&#xff0c;与第三方 API 的集成是非常常见的需求。例如&#xff0c;支付宝、微信等支付平台的支付接口、短信验证码的发送接口、邮件发送接口等。Spring Boot 提供了许多便捷的方式来集成这些第三方 …

Python实战基础17-包

1、pip的安装配置 1.1 pip命令的使用 在安装python时&#xff0c;同时还会安装pip软件&#xff0c;它是python的包管理工具&#xff0c;可以用来查找、下载、安装和卸载python的第三方资源包。 1.2 配置pip 可以直接在终端输入pip命令&#xff0c;如果出错可能会有两个原因…

接口自动化测试实战:JMeter+Ant+Jenkins+钉钉机器人群通知完美结合

目录 前言 一、本地JAVA环境安装配置&#xff0c;安装JAVA8和JAVA17 二、安装和配置Jmeter 三、安装和配置ant 四、jmeter ant配置 五、jenkins安装和配置持续构建项目 文末福利 前言 搭建jmeterantjenkins环境有些前提条件&#xff0c;那就是要先配置好java环境&#…

OS-内存管理-4种内存管理方式(连续分配,页式,段式,段页)。

一&#xff0c;内存管理四种方式。 二&#xff0c;连续分配管理方式。 连续分配方式&#xff1a;为用户分配连续的内存空间。 1.单一连续分配方式 2.固定分区分配方式 3.动态分区分配方式 4.三种连续分配方式的对比。 三&#xff0c;基于页式存储管理。 1.页式 为进一步提高…

【来不及刷题之】32、二分搜索(寻找数,寻找左右边界)

1. 基础二分搜索&#xff1a;寻找一个数 一道很基础的题目&#xff0c;主要注意一下循环条件是 left<right 即可 class Solution {public int search(int[] nums, int target) {int left0;int rightnums.length-1;while(left<right){int midleft(right-left)/2;if(nums…