超越接口:探索Dubbo的泛化调用机制

欢迎来到我的博客,代码的世界里,每一行都是一个故事


在这里插入图片描述

超越接口:探索Dubbo的泛化调用机制

    • 前言
    • 泛化调用的概念
    • Dubbo 中泛化调用的工作原理
    • 泛化实现动态RPC
    • 泛化调用的高级用法
      • 参数和返回值处理
      • 异常处理和错误处理策略
    • controller实践

前言

在现代软件开发中,微服务架构已经成为了一种流行的解决方案。而 Dubbo 作为一种优秀的微服务框架,其强大的功能和灵活性备受开发者青睐。然而,在实际的微服务开发中,我们经常面临着一个挑战:如何在不依赖具体接口的情况下实现动态的远程调用?这就是我们引入 Dubbo 中的泛化调用(Generic Invocation)的时刻!

泛化调用的概念

泛化调用是一种软件设计和编程范式,其核心思想是编写可以适用于多种类型或多种情况的通用代码,从而提高代码的复用性和灵活性。在泛化调用中,通过参数化或抽象化的方式实现通用性,使得代码可以适应不同的数据类型、操作或场景。

具体来说,泛化调用通常通过以下方式实现:

  1. 参数化:通过参数将特定值或行为传递给泛化的代码,使其能够处理不同的输入。这些参数可以是函数、类型、配置选项等。

  2. 抽象化:通过定义抽象接口或抽象类,使得泛化代码能够与不同的实现进行交互,而不需要直接依赖于具体的实现细节。

泛化调用的优势和适用场景包括:

  1. 复用性:泛化调用可以使得代码更加通用,从而可以在不同的上下文中被重复使用,减少代码的重复编写,提高开发效率。

  2. 灵活性:通过泛化调用,可以使得代码更加灵活和可扩展,因为它可以适应不同的需求、数据类型或业务逻辑。

  3. 解耦:泛化调用可以帮助将代码解耦,降低代码之间的依赖关系,使得代码更容易维护和测试。

  4. 适用于多样化的需求:在需要处理多种类型数据或实现多种操作的情况下,泛化调用可以提供一种统一的解决方案,减少代码的复杂度和重复性。

  5. 框架和库的设计:在设计框架或库时,泛化调用是一种常见的设计模式,可以使得框架或库更加通用和灵活,以满足不同用户的需求。

总之,泛化调用是一种强大的编程范式,可以提高代码的复用性、灵活性和可维护性,适用于各种需要通用解决方案的场景。

Dubbo 中泛化调用的工作原理

在 Dubbo 中,泛化调用是指客户端调用服务端的方法时,可以不依赖于服务端接口的具体定义,而是通过指定方法名和参数来实现调用。这种泛化调用的实现原理涉及到 Dubbo 的动态代理机制以及序列化与反序列化过程。

下面是 Dubbo 中泛化调用的工作原理:

  1. 动态代理

    • Dubbo 使用 Java 的动态代理技术,在客户端生成一个代理类,用于与服务端进行通信。
    • 代理类通过拦截客户端的方法调用,并将调用转发给底层的网络通信组件,完成远程调用的过程。
  2. 序列化与反序列化

    • 在泛化调用中,客户端需要将方法名和参数序列化为字节流,并发送给服务端。
    • 服务端接收到字节流后,需要进行反序列化,还原出方法名和参数,并根据方法名执行对应的方法。
    • Dubbo 使用了不同的序列化协议(如 Hessian、JSON、Protobuf 等)来实现序列化和反序列化的过程。
  3. 泛化调用实现

    • Dubbo 提供了 GenericService 接口,用于实现泛化调用。这个接口定义了 invoke 方法,允许客户端传入方法名和参数进行调用。
    • 客户端可以通过获取服务端的 GenericService 对象来实现泛化调用。在 Dubbo 的客户端代理中,可以通过调用 invoke 方法来实现对应的泛化调用。
  4. 服务端实现

    • 在服务端,Dubbo 提供了 GenericService 的实现类,用于处理泛化调用。
    • 这个实现类可以通过反射机制,根据传入的方法名找到对应的实现方法,并调用执行。

总的来说,Dubbo 中泛化调用的实现原理主要涉及动态代理、序列化与反序列化以及泛化调用的实现类。通过这些机制,Dubbo 可以实现对服务端接口定义的解耦,使得客户端可以通过指定方法名和参数来进行调用,从而实现泛化调用的功能。

泛化实现动态RPC

在 Dubbo 中使用泛化调用实现动态 RPC 调用的过程涉及到配置服务提供者和消费者,以及编写示例代码来进行远程调用。

首先,我们来配置 Dubbo 的服务提供者和消费者,使其支持泛化调用:

  1. 服务提供者配置

在服务提供者的配置文件(比如 dubbo-provider.xml)中,需要添加如下配置来开启泛化调用支持:

<dubbo:protocol name="dubbo" port="20880"/>
<dubbo:service interface="com.example.SomeService" ref="someServiceImpl" generic="true"/>

在这里,generic="true" 表示服务提供者将支持泛化调用,并且指定了服务接口 SomeService 的实现类为 someServiceImpl

  1. 服务消费者配置

在服务消费者的配置文件(比如 dubbo-consumer.xml)中,需要添加如下配置来开启泛化调用支持:

<dubbo:reference id="someService" interface="com.example.SomeService" generic="true"/>

在这里,generic="true" 表示服务消费者将支持泛化调用,并且指定了需要引用的服务接口为 SomeService

接下来,我们通过示例代码来演示如何使用泛化调用进行远程调用:

import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.rpc.service.GenericService;

public class GenericConsumer {

    public static void main(String[] args) {
        // 配置应用信息
        ApplicationConfig application = new ApplicationConfig();
        application.setName("generic-consumer");

        // 配置注册中心信息
        RegistryConfig registry = new RegistryConfig();
        registry.setAddress("zookeeper://127.0.0.1:2181");

        // 配置泛化调用
        ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
        reference.setApplication(application);
        reference.setRegistry(registry);
        reference.setInterface("com.example.SomeService"); // 接口名
        reference.setGeneric(true);

        // 获取 GenericService 对象
        GenericService someService = reference.get();

        // 使用泛化调用进行远程调用
        Object result = someService.$invoke("methodName", new String[] {"java.lang.String"}, new Object[] {"parameter"});
        System.out.println("Result: " + result);
    }
}

在这个示例代码中,我们使用 Dubbo 提供的 ReferenceConfigGenericService 类来实现泛化调用。在调用 $invoke 方法时,需要传入方法名、参数类型和参数值来执行远程调用。

需要注意的是,在上面的示例代码中,com.example.SomeService 表示远程服务接口的全限定名,methodName 表示远程方法名,java.lang.String 表示参数类型,parameter 表示参数值。

通过以上配置和示例代码,就可以实现 Dubbo 中的动态 RPC 调用。

泛化调用的高级用法

泛化调用是 Dubbo 提供的一种特殊调用方式,允许调用者以通用的方式调用 Dubbo 服务,而无需事先了解具体的服务接口。在泛化调用中,参数和返回值都是通过序列化和反序列化实现的,因此参数和返回值的处理略有不同于常规的 Dubbo 调用。

参数和返回值处理

  1. 参数处理: 在泛化调用中,参数通常是一个对象数组,对应于方法的参数列表。参数的顺序必须与方法的参数顺序相匹配,并且每个参数的类型必须与方法参数的类型相匹配。参数可以是基本类型、包装类型、字符串、集合等常见类型,也可以是自定义类型。在发起泛化调用时,需要将参数按照方法的参数列表顺序打包成一个对象数组,然后传递给 $invoke 方法。

  2. 返回值处理: 泛化调用的返回值通常是一个对象,可以是基本类型、包装类型、字符串、集合、Map 等常见类型,也可以是自定义类型。在调用 $invoke 方法后,将得到一个 Object 类型的返回值,需要根据实际情况进行类型转换。

异常处理和错误处理策略

  1. 异常处理: 在泛化调用中,如果 Dubbo 服务出现异常,将会抛出 RpcException 异常。因此,在进行泛化调用时,通常需要捕获 RpcException 异常,并根据具体情况进行处理。可以选择将异常信息返回给调用方,或者进行相应的错误处理。

  2. 错误处理策略: 泛化调用中的错误处理策略通常与常规的 Dubbo 调用相同。可以根据业务需求定义错误处理策略,例如重试、回退、降级等。Dubbo 提供了丰富的配置选项,可以灵活地配置错误处理策略,以满足不同的业务场景需求。

总的来说,泛化调用的参数和返回值处理方式与常规 Dubbo 调用类似,但需要注意参数顺序和类型匹配的问题。在异常处理和错误处理方面,需要根据具体情况进行灵活处理,以确保系统的稳定性和可靠性。

controller实践

package fun.bo.controller;

import com.alibaba.fastjson.JSON;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.InvocationTargetException;

@RestController
public class CommonController {

    // 定义URL地址
    @GetMapping("/gateway/{className}/{mtdName}/{parameterTypeName}/{reqBody}")
    public String commonRequest(@PathVariable String className,
                                @PathVariable String mtdName,
                                @PathVariable String parameterTypeName,
                                @PathVariable String reqBody){
        // 将入参的req转为下游方法的入参对象,并发起远程调用
        return commonInvoke(className, mtdName, parameterTypeName, reqBody);
    }

    /**
     * <h2>模拟公共的远程调用方法.</h2>
     *
     * @param className:下游的接口归属方法的全类名。
     * @param mtdName:下游接口的方法名。
     * @param parameterTypeName:下游接口的方法入参的全类名。
     * @param reqParamsStr:需要请求到下游的数据。
     * @return 直接返回下游的整个对象。
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static String commonInvoke(String className,
                                      String mtdName,
                                      String parameterTypeName,
                                      String reqParamsStr) {


        // 然后试图通过类信息对象想办法获取到该类对应的实例对象
        ReferenceConfig<GenericService> referenceConfig = createReferenceConfig(className);
        // 远程调用
        GenericService genericService = referenceConfig.get();
        Object resp = genericService.$invoke(
                mtdName,
                new String[]{parameterTypeName},
                new Object[]{reqParamsStr});
                // new Object[]{JSON.parseObject(reqParamsStr, Map.class)});
        return JSON.toJSONString(resp);
    }

    private static ReferenceConfig<GenericService> createReferenceConfig(String className) {
        DubboBootstrap dubboBootstrap = DubboBootstrap.getInstance();

        // 设置应用服务名称
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName(dubboBootstrap.getApplication().getName());

        // 设置注册中心的地址
        // ApplicationConfig application = dubboBootstrap.getApplication();
        RegistryConfig registryConfig = new RegistryConfig("zookeeper://localhost:2181");
        ReferenceConfig<GenericService> referenceConfig = new ReferenceConfig<>();
        referenceConfig.setApplication(applicationConfig);
        referenceConfig.setRegistry(registryConfig);
        referenceConfig.setInterface(className);

        // 设置泛化调用形式
        referenceConfig.setGeneric("true");
        // 设置默认超时时间5秒
        referenceConfig.setTimeout(6 * 1000);
        return referenceConfig;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

为什么 MySQL 采用 B+ 树作为索引?

资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) 「为什么 MySQL 采用 B 树作为索引&#xff1f;」这句话&#xff0c;是不是在面试时经常出现。 要解释这个问题&#xff0c;其实不单单要从数据结构的角度出发&#xff0c;还要考虑磁盘 I/O 操作次数&am…

C语言-函数指针-快速排序算法(书籍示例-入门)

概述 使用C语言&#xff0c;实现结构体多元素&#xff0c;排序算法&#xff08;冒泡排序&#xff09;&#xff0c;这里使用示例&#xff1a;书籍示例讲解 函数简介 函数声明 void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)) 参…

一维差分数组

797. 差分 输入一个长度为 n 的整数序列。接下来输入 m 个操作&#xff0c;每个操作包含三个整数 l,r,c&#xff0c;表示将序列中 [l,r] 之间的每个数加上 c。 请你输出进行完所有操作后的序列。 输入格式 第一行包含两个整数 n和 m 第二行包含 n个整数&#xff0c;表示整数序…

Redis Stack 安装部署

参考&#xff1a;Run Redis Stack on Docker | Redis Redis-stack 初体验_redis stack-CSDN博客 【docker】运行redis_docker run redis-stack-server requirepass-CSDN博客 Redis Stack 是一组软件套件&#xff0c;它主要由三部分组成。 一个是 Redis Stack Server&#x…

【HTB】 OpenSource

OpenSource 靶机地址&#xff1a;https://app.hackthebox.com/machines/471 信息收集 ┌──(root㉿kali)-[~/Desktop] └─# nmap -Pn -sC -sV -p- 10.129.212.208 --min-rate5000 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-08 16:01 CST Nmap scan report f…

Nginx服务 重写功能与反向代理

六、重写功能 rewrite Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求&#xff0c;此功能依靠 PCRE(perl compatible regular expression)&#xff0c;因此编译之前要安装PCRE库&#xff0c;rewrite是nginx服务器的重要功能之一&#xff0c;用于实现URL的…

Unity 世界坐标、屏幕坐标、UGUI 坐标 相互转换

Unity 世界坐标、屏幕坐标、UGUI 坐标 相互转换坐标转换是游戏开发过程中必不可少的环节 看下图 世界坐标、屏幕坐标、UI 坐标 三种坐标系的转换过程&#xff0c;此文章中的 UI 坐标特指 UGUI 坐标 从上图可以看到&#xff0c;世界坐标 和 UI 坐标 需要通过 屏幕坐标作为中间转…

MemberPress配置和使用会员登录页面

目录 隐藏 创建会员登录页面 编辑登录页面 设计您的登录页面 链接到您的登录页面 创建会员登录页面 要创建MemberPress会员登录页面&#xff0c;您需要做的就是导航到 MemberPress > 设置 > 页面选项卡&#xff0c;然后在页面顶部附近的“MemberPress 登录页面”…

面试官脑子有病系列:为什么 HashMap 是线程不安全的?

文章目录 前言HashMap为啥线程不安全&#xff1f;HashMap线程不安全的根本原因put 方法中的非原子性操作扩容时的非原子性操作 安全的HashMap总结 前言 Hi&#xff0c;大家好&#xff0c;我是王二蛋。 我们在面试的时候&#xff0c;经常会被问到一些有的没的、看似高深但与日…

科技型中小企业怎么做

在当今快速发展的科技时代&#xff0c;科技型中小企业扮演着越来越重要的角色。这些企业不仅推动了技术创新&#xff0c;还为经济增长和社会进步做出了巨大贡献。那么&#xff0c;科技型中小企业应如何制定并执行其发展战略呢&#xff1f; 1. 明确定位与战略规划 对于任何企业…

SD-WAN为出海电商提供了什么支持

出海电商行业的持续发展与壮大&#xff0c;使得网络连接的稳定性和效率成为其成功的关键因素。SD-WAN&#xff08;软件定义广域网&#xff09;作为一种先进的网络解决方案&#xff0c;为出海电商提供了诸多优势和支持。 首先&#xff0c;SD-WAN通过智能路由技术&#xff0c;能够…

华火电焰灶测评:电焰灶十大品牌哪个好?实力排名怎么样?

华火新能源电焰灶作为现代厨房技术的一大创新&#xff0c;近年来受到了广泛关注。在新能源电焰灶市场中&#xff0c;目前只有华火品牌具有独立研发、独立生产、品质背书、完善服务等雄厚的综合实力&#xff1b;而华火品牌凭借其独特的技术和优势&#xff0c;与其他传统燃气灶品…

EDM邮件群发推广多少钱?有哪些优势?

电子邮件营销&#xff08;Electronic Direct Mail, EDM&#xff09;以其高性价比、精准定向与可度量效果的优势&#xff0c;成为众多企业不可或缺的营销策略。云衔科技&#xff0c;作为企业数字广告营销和SaaS软件服务的领军者&#xff0c;以其创新的智能EDM邮件营销系统解决方…

2024 工业物联网通信与网络安全国际学术会议(IIOTNS 2024)

【会议英文官网】&#xff1a;www.iiotns2024.org 【会议时间】&#xff1a; 2024年5月10-12日 【一轮截稿时间】&#xff1a; 2024年3月10-12日 所有于一轮截稿时间之前投稿&#xff0c;后续通过审核并被大会录用的稿件享早鸟优惠&#xff1a;单篇立减400元&#xff01;&am…

如何快速识别陶瓷件的外观缺陷吗?

陶瓷件由陶瓷材料制成的物品或零部件&#xff0c;通常用于装饰、日常生活用品、工艺品或工业应用。陶瓷是一种非金属材料&#xff0c;具有耐高温、耐磨损、绝缘、化学稳定等特性&#xff0c;因此在许多领域得到广泛应用。 本案针对陶瓷件尺寸长25mm*宽11mm*高2mm的产品的外观检…

HarmonyOS 应用开发-ArkUI事件机制

ArkUI提供了事件机制&#xff0c;这些事件提供了不同的信息用于处理程序交互逻辑&#xff0c;ArKUI事件按照功能来讲&#xff0c;可以分为以下几种&#xff1a; 点击事件触摸事件挂载卸载事件拖拽事件按键事件焦点事件鼠标事件组件区域变化事件组件可见区域变化事件组件快捷键…

C++ primer 第十八章

C语言的三大特性&#xff1a;异常处理、命名空间、多重继承。 1.异常处理 异常处理机制允许我们能够将问题的检测与解决过程分离开来。 1.1、抛出异常 在C语言中&#xff0c;我们通过抛出一条表达式来引发一个异常。 当执行一个throw时&#xff0c;程序的控制权从throw转移…

T527 Qt 触摸 ----- TSLIB

一、调试 1、驱动路径 bsp/drivers/input/ctp/gt9xx/gt9xx_ts.c 2、硬件接口 挂载在TWI0下 3、中断复位脚 4、设备树 &twi0 {clock-frequency <400000>;pinctrl-0 <&twi0_pins_default>;pinctrl-1 <&twi0_pins_sleep>;pinctrl-names &quo…

SpringBoot 定时任务实践、定时任务按指定时间执行

Q1. springboot怎样创建定时任务&#xff1f; 很显然&#xff0c;人人都知道&#xff0c;Scheduled(cron ".....") Q2. 如上所示创建了定时任务却未能执行是为什么&#xff1f; 如果你的cron确定没写错的话 cron表达式是否合法&#xff0c;可参考此处&#xff0c…

MAC苹果电脑如何使用Homebrew安装iperf3

一、打开mac终端 找到这个终端打开 二、终端输入安装Homebrew命令 Homebrew官网地址&#xff1a;https://brew.sh/ 复制这个命令粘贴到mac的终端窗口&#xff0c;然后按回车键 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/in…