DUBBO 3.x 兼容 invoke 调用

news2024/11/27 1:45:54

从DUBBO的2.7.22版本升级到了3.x的版本后,发现invoke失灵了

首先是启动报错,注释掉配置 dubbo.protocol.telnet=invoke后程序可运行,但是invoke失效。

通过对比源码

示例:

tag-3.0.10

tag-2.7.22

 发现3.0.2之后的版本都移除了invoke指令。

那么问题就很简单了,把这部分拿回来就好了!!

此时参考下面文章和源码

Dubbo3 Telnet 命令扩展_w3cschool

添加如下内容

首先在 resource/META-INF下添加文件

文件名称:org.apache.dubbo.remoting.telnet.TelnetHandler

我的目录是

 填充内容

# xxx替换为任意包路径
invoke=xxx.InvokeTelnetHandler

在xxx目录(和上面的包路径保持一致)下添加如下两个类

InvokeTelnetHandler

package xxx;

import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.JsonUtils;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.qos.legacy.ChangeTelnetHandler;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.telnet.TelnetHandler;
import org.apache.dubbo.remoting.telnet.support.Help;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.MethodDescriptor;
import org.apache.dubbo.rpc.model.ProviderModel;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.apache.dubbo.common.utils.PojoUtils.realize;

/**
 * InvokeTelnetHandler
 */
@Activate
@Help(parameter = "[service.]method(args) ", summary = "Invoke the service method.",
        detail = "Invoke the service method.")
public class InvokeTelnetHandler implements TelnetHandler {

    public static final String INVOKE_MESSAGE_KEY = "telnet.invoke.method.message";
    public static final String INVOKE_METHOD_LIST_KEY = "telnet.invoke.method.list";
    public static final String INVOKE_METHOD_PROVIDER_KEY = "telnet.invoke.method.provider";

    @Override
    @SuppressWarnings("unchecked")
    public String telnet(Channel channel, String message) {
        if (StringUtils.isEmpty(message)) {
            return "Please input method name, eg: \r\ninvoke xxxMethod(1234, \"abcd\", {\"prop\" : \"value\"})\r\n" +
                    "invoke XxxService.xxxMethod(1234, \"abcd\", {\"prop\" : \"value\"})\r\n" +
                    "invoke com.xxx.XxxService.xxxMethod(1234, \"abcd\", {\"prop\" : \"value\"})";
        }

        String service = (String) channel.getAttribute(ChangeTelnetHandler.SERVICE_KEY);

        int i = message.indexOf("(");

        if (i < 0 || !message.endsWith(")")) {
            return "Invalid parameters, format: service.method(args)";
        }

        String method = message.substring(0, i).trim();
        String args = message.substring(i + 1, message.length() - 1).trim();
        i = method.lastIndexOf(".");
        if (i >= 0) {
            service = method.substring(0, i).trim();
            method = method.substring(i + 1).trim();
        }

        List<Object> list;
        try {
            list = JsonUtils.getJson().toJavaList("[" + args + "]", Object.class);
        } catch (Throwable t) {
            return "Invalid json argument, cause: " + t.getMessage();
        }
        StringBuilder buf = new StringBuilder();
        Method invokeMethod = null;
        ProviderModel selectedProvider = null;
        if (isInvokedSelectCommand(channel)) {
            selectedProvider = (ProviderModel) channel.getAttribute(INVOKE_METHOD_PROVIDER_KEY);
            invokeMethod = (Method) channel.getAttribute(SelectTelnetHandler.SELECT_METHOD_KEY);
        } else {
            for (ProviderModel provider : ApplicationModel.allProviderModels()) {
                if (!isServiceMatch(service, provider)) {
                    continue;
                }

                selectedProvider = provider;
                List<Method> methodList = findSameSignatureMethod(provider.getAllMethods(), method, list);
                if (CollectionUtils.isEmpty(methodList)) {
                    break;
                }

                if (methodList.size() == 1) {
                    invokeMethod = methodList.get(0);
                } else {
                    List<Method> matchMethods = findMatchMethods(methodList, list);
                    if (CollectionUtils.isEmpty(matchMethods)) {
                        break;
                    }
                    if (matchMethods.size() == 1) {
                        invokeMethod = matchMethods.get(0);
                    } else { //exist overridden method
                        channel.setAttribute(INVOKE_METHOD_PROVIDER_KEY, provider);
                        channel.setAttribute(INVOKE_METHOD_LIST_KEY, matchMethods);
                        channel.setAttribute(INVOKE_MESSAGE_KEY, message);
                        printSelectMessage(buf, matchMethods);
                        return buf.toString();
                    }
                }
                break;
            }
        }


        if (!StringUtils.isEmpty(service)) {
            buf.append("Use default service ").append(service).append(".");
        }
        if (selectedProvider == null) {
            buf.append("\r\nNo such service ").append(service);
            return buf.toString();
        }
        if (invokeMethod == null) {
            buf.append("\r\nNo such method ").append(method).append(" in service ").append(service);
            return buf.toString();
        }
        try {
            Object[] array = realize(list.toArray(), invokeMethod.getParameterTypes(),
                    invokeMethod.getGenericParameterTypes());
            long start = System.currentTimeMillis();
            AppResponse result = new AppResponse();
            try {
                Object o = invokeMethod.invoke(selectedProvider.getServiceInstance(), array);
                result.setValue(o);
            } catch (Throwable t) {
                result.setException(t);
            }
            long end = System.currentTimeMillis();
            buf.append("\r\nresult: ");
            buf.append(JsonUtils.getJson().toJson(result.recreate()));
            buf.append("\r\nelapsed: ");
            buf.append(end - start);
            buf.append(" ms.");
        } catch (Throwable t) {
            return "Failed to invoke method " + invokeMethod.getName() + ", cause: " + StringUtils.toString(t);
        }
        return buf.toString();
    }


    private boolean isServiceMatch(String service, ProviderModel provider) {
        return provider.getServiceKey().equalsIgnoreCase(service)
                || provider.getServiceInterfaceClass().getSimpleName().equalsIgnoreCase(service)
                || provider.getServiceInterfaceClass().getName().equalsIgnoreCase(service)
                || StringUtils.isEmpty(service);
    }

    private List<Method> findSameSignatureMethod(Set<MethodDescriptor> methods, String lookupMethodName, List<Object> args) {
        List<Method> sameSignatureMethods = new ArrayList<>();
        for (MethodDescriptor model : methods) {
            Method method = model.getMethod();
            if (method.getName().equals(lookupMethodName) && method.getParameterTypes().length == args.size()) {
                sameSignatureMethods.add(method);
            }
        }
        return sameSignatureMethods;
    }

    private List<Method> findMatchMethods(List<Method> methods, List<Object> args) {
        List<Method> matchMethod = new ArrayList<>();
        for (Method method : methods) {
            if (isMatch(method, args)) {
                matchMethod.add(method);
            }
        }
        return matchMethod;
    }

    private static boolean isMatch(Method method, List<Object> args) {
        Class<?>[] types = method.getParameterTypes();
        if (types.length != args.size()) {
            return false;
        }
        for (int i = 0; i < types.length; i++) {
            Class<?> type = types[i];
            Object arg = args.get(i);

            if (arg == null) {
                if (type.isPrimitive()) {
                    return false;
                }

                // if the type is not primitive, we choose to believe what the invoker want is a null value
                continue;
            }

            if (ReflectUtils.isPrimitive(arg.getClass())) {
                // allow string arg to enum type, @see PojoUtils.realize0()
                if (arg instanceof String && type.isEnum()) {
                    continue;
                }

                if (!ReflectUtils.isPrimitive(type)) {
                    return false;
                }

                if (!ReflectUtils.isCompatible(type, arg)) {
                    return false;
                }
            } else if (arg instanceof Map) {
                String name = (String) ((Map<?, ?>) arg).get("class");
                if (StringUtils.isNotEmpty(name)) {
                    Class<?> cls = ReflectUtils.forName(name);
                    if (!type.isAssignableFrom(cls)) {
                        return false;
                    }
                } else {
                    return true;
                }
            } else if (arg instanceof Collection) {
                if (!type.isArray() && !type.isAssignableFrom(arg.getClass())) {
                    return false;
                }
            } else {
                if (!type.isAssignableFrom(arg.getClass())) {
                    return false;
                }
            }
        }
        return true;
    }

    private void printSelectMessage(StringBuilder buf, List<Method> methods) {
        buf.append("Methods:\r\n");
        for (int i = 0; i < methods.size(); i++) {
            Method method = methods.get(i);
            buf.append(i + 1).append(". ").append(method.getName()).append("(");
            Class<?>[] parameterTypes = method.getParameterTypes();
            for (int n = 0; n < parameterTypes.length; n++) {
                buf.append(parameterTypes[n].getSimpleName());
                if (n != parameterTypes.length - 1) {
                    buf.append(",");
                }
            }
            buf.append(")\r\n");
        }
        buf.append("Please use the select command to select the method you want to invoke. eg: select 1");
    }

    private boolean isInvokedSelectCommand(Channel channel) {
        if (channel.hasAttribute(SelectTelnetHandler.SELECT_KEY)) {
            channel.removeAttribute(SelectTelnetHandler.SELECT_KEY);
            return true;
        }
        return false;
    }
}

 SelectTelnetHandler

package xxx;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.telnet.TelnetHandler;
import org.apache.dubbo.remoting.telnet.support.Help;
import java.lang.reflect.Method;
import java.util.List;

/**
 * SelectTelnetHandler
 */
@Activate
@Help(parameter = "[index]", summary = "Select the index of the method you want to invoke.",
        detail = "Select the index of the method you want to invoke.")
public class SelectTelnetHandler implements TelnetHandler {
    public static final String SELECT_METHOD_KEY = "telnet.select.method";
    public static final String SELECT_KEY = "telnet.select";

    private InvokeTelnetHandler invokeTelnetHandler = new InvokeTelnetHandler();

    @Override
    @SuppressWarnings("unchecked")
    public String telnet(Channel channel, String message) {
        if (message == null || message.length() == 0) {
            return "Please input the index of the method you want to invoke, eg: \r\n select 1";
        }
        List<Method> methodList = (List<Method>) channel.getAttribute(InvokeTelnetHandler.INVOKE_METHOD_LIST_KEY);
        if (CollectionUtils.isEmpty(methodList)) {
            return "Please use the invoke command first.";
        }
        if (!StringUtils.isNumber(message) || Integer.parseInt(message) < 1 || Integer.parseInt(message) > methodList.size()) {
            return "Illegal index ,please input select 1~" + methodList.size();
        }
        Method method = methodList.get(Integer.parseInt(message) - 1);
        channel.setAttribute(SELECT_METHOD_KEY, method);
        channel.setAttribute(SELECT_KEY, Boolean.TRUE);
        String invokeMessage = (String) channel.getAttribute(InvokeTelnetHandler.INVOKE_MESSAGE_KEY);
        return invokeTelnetHandler.telnet(channel, invokeMessage);
    }
}

此时在启动,测试 telnet 下invoke调用就可以啦!

( 这两个类是我基于3.0.1的版本和我的版本做过适配的,如果有报错请自行解决。)

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

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

相关文章

【网络编程】UDP简单实现翻译软件与网络聊天室

文章目录 一、引入二、翻译软件实现2.1 加载字典2.2 处理数据并传递给用户端2.3 客户端获取结果2.4 结果2.5 执行命名功能 三、网络聊天室实现3.1 管理用户3.2 发送消息3.3 多线程处理3.4 结果 四、源码 一、引入 在上一章【网络编程】demo版UDP网络服务器实现实现了客户端和服…

(1分钟了解)视觉惯性导航初始化方法综述

视觉惯性导航初始化方法综述 ​ 编辑切换为居中 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 初始化相关的简介&#xff0c;在这里知道初始化方法可以分为联合初始化、非联合初始化和半联合初始化三种方法即可。 ​ 编辑切换为居中 添加图片注释&…

VIM学习笔记 正则表达式-(vimgrep/grep)

在UNIX问世的前一年&#xff0c;1969年&#xff0c;Ken Thompson将正则表达式整合入QED文本编辑器。在Linux文本编辑器ed中&#xff0c;如果你希望显示包含字母“re”的行时&#xff0c;需要使用命令g/re/p&#xff0c;而grep也因此得名。可以看作此操作的缩写&#xff1a;g (g…

ARM板上的蓝牙对讲功能

1&#xff09;ARMRTL8723 或RTL8821 RTL8723是USB接口的邮票芯片&#xff0c;集成了wifi和BT。前面已经完成了wifi的处理&#xff0c;这次主要说一下蓝牙语音方面。 蓝牙功能&#xff0c;我们主要是使用Bluez5协议栈.结合alsa使用&#xff08;pulseaudio也是可以的&#xff0c…

JVM学习(四)

1. JAVA IO/NIO 1.1. 阻塞 IO 模型 最传统的一种 IO 模型&#xff0c;即在读写数据过程中会发生阻塞现象。当用户线程发出 IO 请求之后&#xff0c;内 核会去查看数据是否就绪&#xff0c;如果没有就绪就会等待数据就绪&#xff0c;而用户线程就会处于阻塞状态&#xff0c…

Class 02 - R语言Rstudio的安装

Class 02 - R语言&Rstudio的安装 下载和安装R安装前准备下载R语言安装R语言开始使用R语言 下载和安装RStudio安装前准备下载RStudio安装RStudio开始使用RStudio如何编写代码 下载和安装R 在这个部分中&#xff0c;你将完成在计算机上下载和安装R语言程序。当安装完成后&am…

嫌视频背景杂乱或单调?如何去除视频杂乱背景

录制视频时&#xff0c;有时候视频背景会十分杂乱或单调&#xff0c;这会对用户的视觉体验和注意力产生负面影响。 背景杂乱或单调的场景可能会影响您的观感。这种情况通常发生在自然光线不足或拍摄环境不理想的情况下。如果您想改变视频的背景或者是去除视频杂乱的背景&#…

硬件I2C读写MPU6050代码

1、接线图 SDA接在B11,SCL接在B10 &#xff0c;软件IIC的两个引脚可以任意更改的&#xff0c;因为都是开漏输出&#xff0c;硬件接在哪个引脚上&#xff0c;程序中就对应操作哪个引脚 但是硬件IIC&#xff0c;通信引脚是不可以任意指定的&#xff0c;查表&#xff0c;由于PB6、…

2023年Android开发者路线-第4部分

2023年Android开发者路线-第1部分 2023年Android开发者路线-第2部分 2023年Android开发者路线-第3部分 2023年Android开发者路线-第4部分 2023年Android开发者路线-第4部分 在上一篇博文中&#xff0c;我们讨论了现代 Android 开发的基本要素&#xff0c;包括 Fragments、…

2023年Android开发者路线-第3部分

2023年Android开发者路线-第1部分 2023年Android开发者路线-第2部分 2023年Android开发者路线-第3部分 2023年Android开发者路线-第4部分 2023年Android开发者路线-第3部分 在上一篇文章中&#xff0c;我们讨论了 Android 主要组件的重要元素&#xff0c;包括 Intents 和 …

【C++初阶】类与对象(中)之你必须掌握的三个重要默认成员函数 --- 构造函数 +析构函数 + 拷贝构造函数

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

chatgptH5源码开发

hatGPTH5源码开发需要以下步骤&#xff1a; 确定需求&#xff1a;在开发ChatGPTH5应用之前&#xff0c;需要明确用户的需求和目标&#xff0c;以便进行合理的设计和开发。 技术选型&#xff1a;选择适合的前端技术框架和工具&#xff0c;如React、Vue、Angular等&#…

Flink从入门到精通之-10容错机制

Flink从入门到精通之-10容错机制 流式数据连续不断地到来&#xff0c;无休无止&#xff1b;所以流处理程序也是持续运行的&#xff0c;并没有一个明确的结束退出时间。机器运行程序&#xff0c;996 起来当然比人要容易得多&#xff0c;不过希望“永远运行”也是不切实际的。因…

WritingGPT: 基于ChatGPT和AutoGPT打造个人写作团队

本文介绍了如何通过定义多个GPT角色&#xff0c;以自动化流水线的方式打造个人写作团队&#xff0c;让AI帮助我们完成文章写作、修改、SEO等所有流程。原文: How I Built WritingGPT, a Fully Automated AI Writing Team ChatGPT是AI内容创造领域的巨大飞跃&#xff0c;但当我们…

8 种「Python 程序」定时执行方式

在日常工作中&#xff0c;我们常常会用到需要周期性执行的任务&#xff0c;一种方式是采用 Linux 系统自带的 crond 结合命令行实现&#xff0c;另外一种方式是直接使用Python。 最近我整理了一下 Python 定时任务的实现方式&#xff0c;建议收藏后学习。 利用while True: sle…

pro如何添加定时任务

Pro v2.4版本开始后台可以开关控制定时任务&#xff0c;那如何添加新的定时任务呢&#xff1f; 第一步&#xff1a;设置定时任务名称及标识&#xff1b; 文件app\controller\admin\v1\system\SystemTimer中task_name()方法 /**定时任务名称及标识 * return mixed */ public fu…

25岁,本科学历,待业,如何成为优秀的数据分析师,值得关注!

25岁&#xff0c;本科学历&#xff0c;待业&#xff0c;如何成为优秀的数据分析师&#xff0c;值得关注&#xff01; 你是在工作几年后确定自己的职业方向的呢&#xff1f;还是一直都是处于迷茫&#xff0c;随波逐流的状态&#xff1f;都说谁的青春不迷茫&#xff0c;但时间是最…

服务限流方案总结

流控作用 一般的做后台服务的&#xff0c;都会接触到流控&#xff0c;一般的场景就是在流量异常&#xff0c;比如遭受攻击的时候&#xff0c;保障服务不过载&#xff0c;在可支持的范围内提供稳定的服务。比如我们的服务支持100QPS&#xff0c;当一下子来了1000个请求的时候&a…

全景 I 0基础学习VR全景制作,平台篇第22篇 热点功能—作品功能操作

本期为大家带来蛙色VR平台&#xff0c;热点功能—作品功能操作。 功能位置示意 热点&#xff0c;指在全景作品中添加各种类型图标的按钮&#xff0c;引导用户通过按钮产生更多的交互&#xff0c;增加用户的多元化体验。 作品热点&#xff0c;即全景项目跳转热点&#xff0c;可与…

您使用的ChatGPT错了!以下是如何领先于 99% 的 ChatGPT 用户

我们大多数人都错误地使用了 ChatGPT&#xff1a; 错误1&#xff1a;不在提示中包含示例。 错误2&#xff1a;忽略通过角色控制 ChatGPT 的行为。 错误3&#xff1a;让 ChatGPT 猜测内容&#xff0c;而不是向它提供一些信息。 通过3类有用的prompt工程掌握 ChatGPT的使用。 …