热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【手写dubbo4】想了解dubbo的Invocation模型?先创造个私有协议吧!

上个版本只是为了实现简单的远程调用,只能请求指定类,并且返回字符串。本次优化,使得可以请求服务端开放的任意服务,并且返回任意

        上个版本只是为了实现简单的远程调用,只能请求指定类,并且返回字符串。本次优化,使得可以请求服务端开放的任意服务,并且返回任意对象。
        优化请求信息,请求信息中携带消息id(作用很大,稍后会有介绍)、接口名、方法名、参数信息等。响应信息中有消息id、响应信息等。对象序列化方式暂时采用jdk自带序列化,因序列化不影响使用,因此暂不优化,以后版本提供扩展入口。


优化思路图

image-20210512164115390


项目结构


  • dubbo-server: 服务端
  • dubbo-client: 消费端
  • dubbo-server-service: 接口信息,消费端引入此模块
  • dubbo-framework: dubbo框架模块。

核心代码

        因请求和响应传输的对象不同。因此定义为request/response两个对象名称为DubboRequestDubboResponse

        每次请求都需要有一个id,也许这个id不需要全局唯一,但是在同一时间,不能存在同样id的请求,这个原因,我会在下一篇文章种重点说明。这里采用AtomicgetAndIncrement方法获取id,主要是为了即使在多线程的情况下,也可以安全的获取到唯一的标识,这里不了解Atomic包下类作用的,可以自行百度下。

public class DubboRequest implements Serializable
{private static final AtomicLong INVOKE_ID = new AtomicLong(0);private final long mId;private Object mData;public DubboRequest (){this.mId = newId();}private static final long newId (){//每次请求都有一个请求编号,每次获取一次请求编号+1。//getAndIncrement 获取并+1。 当到最大值时再次获取,会自动更新到最小值。因此始终不会重复return INVOKE_ID.getAndIncrement();}
}

        在DubboRequest的mData中存放RpcInvocation对象。这个对象的名字也很有深意。有兴趣的小伙伴可以百科下Invacation模型。

public class RpcInvocation implements Serializable
{private static final long serialVersionUID &#61; -4355285085441097045L;//接口路径private String interfacePath;//方法名称private String methodName;//参数类型private Class<?>[] parameterTypes;//参数值private Object[] arguments;//附加属性private Map<String, String> attachments;
}

public class DubboResponse implements Serializable
{private long mId;private Object mData;
}

        为了容易理解&#xff0c;协议的信息&#xff0c;还继续采用简单方式。一个Int类型的值存放总数据大小&#xff0c;然后后面是字节数组。

image-20210512172009080

DubboClientEncoder.java编码代码。

public class DubboClientEncoder extends MessageToByteEncoder<DubboRequest>
{&#64;Overrideprotected void encode(ChannelHandlerContext ctx, DubboRequest req, ByteBuf out) throws Exception {byte[] serialize &#61; SerializeUtil.serialize (req);out.writeInt(serialize.length);out.writeBytes(serialize);}
}

        服务开放方式&#xff0c;为了使得协议更加容易理解&#xff0c;暂时使用简陋的方式&#xff0c;简单存放在map中。

private static final Map<String,Class> exportServiceMap &#61; new HashMap<> ();static {//假设此为开放的服务&#xff0c;稍后优化。exportServiceMap.put ("com.test.dubbo.service.UserService",UserServiceImpl.class);exportServiceMap.put ("com.test.dubbo.service.OrderService", OrderServiceImpl.class);}

        服务端接收到请求信息时&#xff0c;对请求信息进行解码&#xff0c;并且找到对应的接口调用并且返回。

&#64;Overrideprotected void channelRead0 (ChannelHandlerContext ctx, DubboRequest req)throws Exception{//获取客户端发送的消息&#xff0c;并调用服务DubboResponse rsp &#61; new DubboResponse ();RpcInvocation rpc &#61;(RpcInvocation) req.getMData ();rsp.setMId (req.getMId ());Class aClass &#61; exportServiceMap.get (rpc.getInterfacePath ());if(aClass!&#61;null){Method method &#61; aClass.getMethod (rpc.getMethodName (), rpc.getParameterTypes ());Object invoke &#61; method.invoke (aClass.newInstance (), rpc.getArguments ());rsp.setMData (invoke);}ctx.writeAndFlush (rsp);}

客户端调用代码&#xff0c;调用服务端的两个接口&#xff0c;响应结果打印。

public static void main (String[] args){RpcProxy rpcProxy &#61; new RpcProxy();UserService bean &#61; rpcProxy.getBean (UserService.class);User user &#61; bean.getUserNameById (12l);System.out.println ("userName:"&#43;user.getName ());OrderService orderService &#61; rpcProxy.getBean (OrderService.class);List<Order> orderList &#61; orderService.getOrderList ();System.out.println ("orders:"&#43;orderList);}

如此一来&#xff0c;通过RpcInvocation更加深入了解了Invocation的作用。
源码地址&#xff1a;gitee


推荐阅读
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • Java编程思想一书中第21章并发中关于线程间协作的一节中有个关于汽车打蜡与抛光的小例子(原书的704页)。这个例子主要展示的是两个线程如何通过wait ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 微软评估和规划(MAP)的工具包介绍及应用实验手册
    本文介绍了微软评估和规划(MAP)的工具包,该工具包是一个无代理工具,旨在简化和精简通过网络范围内的自动发现和评估IT基础设施在多个方案规划进程。工具包支持库存和使用用于SQL Server和Windows Server迁移评估,以及评估服务器的信息最广泛使用微软的技术。此外,工具包还提供了服务器虚拟化方案,以帮助识别未被充分利用的资源和硬件需要成功巩固服务器使用微软的Hyper - V技术规格。 ... [详细]
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • centos安装Mysql的方法及步骤详解
    本文介绍了centos安装Mysql的两种方式:rpm方式和绿色方式安装,详细介绍了安装所需的软件包以及安装过程中的注意事项,包括检查是否安装成功的方法。通过本文,读者可以了解到在centos系统上如何正确安装Mysql。 ... [详细]
  • vb.net不用多线程如何同时运行两个过程?不用多线程?即使用多线程,也不会是“同时”执行,题主只要略懂一些计算机编译原理就能明白了。不用多线程更不可能让两个过程同步执行了。不过可 ... [详细]
author-avatar
常依sunrise
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有