Netty之自定义RPC

需求分析

使用netty实现方法远程调用, 在client调用本地接口中方法时, 使用反射进行远程调用, server执行完结果后, 将执行结果进行封装, 发送到client

RPC调用模型:

在这里插入图片描述

1. 服务消费方(client)以本地调用方式调用服务 
2. client stub 接收到调用后负责将方法、参数等封装成能够进行网络传输的消息体 
3. client stub 将消息进行编码并发送到服务端 
4. server stub 收到消息后进行解码 
5. server stub 根据解码结果调用本地的服务 
6. 本地服务执行并将结果返回给 server stub 
7. server stub 将返回导入结果进行编码并发送至消费方 
8. client stub 接收到消息并进行解码 
9. 服务消费方(client)得到结果

自定义RPC结构

在这里插入图片描述
根据上面执行流程图, 编写代码
定义request消息结构:

/*** 封装class信息, 用于反射过程, 封装client的request*/
public class ClassInfo implements Serializable {private String className;private String methodName;//参数类型private Class<?>[] type;//参数列表private Object[] objects;public ClassInfo(String className, String methodName, Class<?>[] type, Object[] objects) {this.className = className;this.methodName = methodName;this.type = type;this.objects = objects;}public String getClassName() {return className;}public String getMethodName() {return methodName;}public Class<?>[] getType() {return type;}public Object[] getObjects() {return objects;}
}

Client

client接口:

public interface HelloRpc {String hello(String name);
}

client的代理类:

public class NettyRpcProxy {/*** 创建代理对象* @param target* @return*/public static Object create(Class target) {//动态代理, 在代理过程中执行远程数据发送return Proxy.newProxyInstance(target.getClassLoader(), new Class[]{target},(proxy, method, args) -> {//定义要调用哪一个方法的信息ClassInfo classInfo = new ClassInfo(target.getName(), method.getName(), method.getParameterTypes(), args);NioEventLoopGroup workGroup = new NioEventLoopGroup();MyClientResultHandler myClientResultHandler = new MyClientResultHandler();Bootstrap bootstrap = new Bootstrap().group(workGroup).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast("encoder", new ObjectEncoder());pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));pipeline.addLast(myClientResultHandler);}});ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 9999).sync();//client进行发送channelFuture.channel().writeAndFlush(classInfo).sync();channelFuture.channel().closeFuture().sync();return myClientResultHandler.getResponse();});}
}

client的handler:

public class MyClientResultHandler extends ChannelInboundHandlerAdapter {private Object response;public Object getResponse() {return response;}//读取从Server发送过来的执行结果@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {response = msg;ctx.close();}
}

Server

server接口(该接口与client的接口是一样的):

public interface HelloRpc {String hello(String name);
}

server接口实现类:

public class HelloRpcImpl implements HelloRpc {@Overridepublic String hello(String name) {return "hello" + name;}
}

server端:

/*** 网络处理服务器*/
public class NettyRpcServer {private final int port;public NettyRpcServer(int port) {this.port = port;}public void start() {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workGroup = new NioEventLoopGroup();ServerBootstrap serverBootstrap = new ServerBootstrap().group(bossGroup, workGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();//对象编码器, 底层使用Java序列化, 效率低下, 通常使用protobufpipeline.addLast("encoder", new ObjectEncoder());pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));pipeline.addLast(new MyInvokeHandler());}});try {ChannelFuture channelFuture = serverBootstrap.bind(port).sync();System.out.println("server is ready");channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {bossGroup.shutdownGracefully();workGroup.shutdownGracefully();}}public static void main(String[] args) {new NettyRpcServer(9999).start();}}

server的MyInvokeHandler(解析从client发送的内容):

/*** 封装client调用方法后执行结果*/
public class MyInvokeHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {//使用反射机制, 调用本地方法实现类, 将方法执行结果封装, 发送至clientClassInfo classInfo = (ClassInfo) msg;Object clazz = Class.forName(this.getImplClassName(classInfo)).newInstance();Method method = clazz.getClass().getMethod(classInfo.getMethodName(), classInfo.getType());Object result = method.invoke(clazz, classInfo.getObjects());ctx.writeAndFlush(result);}//根据ClassInfo反射获取对应method执行结果private String getImplClassName(ClassInfo classInfo) throws ClassNotFoundException {String interfacePath = "com.regotto.test.netty_test_rpc.server.fun";int lastIndexOf = classInfo.getClassName().lastIndexOf(".");String interfaceName = classInfo.getClassName().substring(lastIndexOf);Class superClass = Class.forName(interfacePath + interfaceName);Reflections reflections = new Reflections(interfacePath);//获得该接口下的所有实现类Set<Class<?>> implClassSet = reflections.getSubTypesOf(superClass);if (implClassSet.size() == 0) {System.out.println("未找到实现类, erro");return null;} else if (implClassSet.size() > 1) {System.out.println("实现类存在多个, 未指明使用哪一个");return null;}return (implClassSet.toArray(new Class[0]))[0].getName();}
}

Client测试类

/*** 测试*/
public class TestNettyRpc {public static void main(String[] args) {//反射调用HelloNetty helloNetty = (HelloNetty) NettyRpcProxy.create(HelloNetty.class);System.out.println(helloNetty.hello());}
}

执行结果:
在这里插入图片描述

总结

RPC机制:
1.Client使用动态代理机制, 将本地接口信息编码封装发送至Server
2.Server将接收到的信息解码, 根据反射机制获得方法执行结果, 然后将执行结果编码封装发送至Client
3.Client解析Server发送的执行结果

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

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

相关文章

vue垂直布局_vue实现长图垂直居上 vue实现短图垂直居中

大致效果如下图&#xff0c;只考虑垂直方向。长图可以通过滚动条看&#xff0c;短图居中效果&#xff0c;布局合理html代码(vue作用域内)&#xff1a;css代码&#xff1a;.box{height: 100%;//如高度等于网页高度overflow: auto;display: flex;flex-direction: column;justify-…

samba 服务器搭建

为什么要搭建samba 服务器我在 windows 下安装了个虚拟机&#xff0c;然后想两边同步下资料&#xff0c;原来虚拟机是可以共享文件的&#xff0c;可是不知道什么见鬼了&#xff0c;就是不行&#xff0c;没办法了&#xff0c;我只好拿出我的杀手锏&#xff0c;安装 samba。这个在…

Codis的源码编译生成tar包

一、Go环境的安装 1、下载地址 https://golang.org/dl/2、解压 tar -zxvf go1.7.1.linux-amd64.tar.gz -C /usr/local 3、修改配置文件   vi /etc/profile     export GOROOT/usr/local/go     export GOPATH/usr/local/data/go     export PATH$PATH:$GOROOT/b…

一直想说的,技术职业化

最近后台有人一直跟我说&#xff0c;为什么不好好写一篇技术比较强的文章&#xff0c;说实话&#xff0c;最近时间比较紧张&#xff0c;早上 8 点出门&#xff0c;晚上12点左右到家。刚好今天整理了一个不错文章的列表&#xff0c;明天发出来&#xff0c;希望给学习的同学们有点…

MyBatis初级入门及常见问题

入门案例 创建maven工程 项目目录结构: 首先在maven的pom.xml导入Mybatis和MySQL的依赖坐标: <dependencies><!--Junit测试依赖--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</…

科沃斯机器人招股_科沃斯机器人首次公开发行A股股票的初步询价公告

随着科沃斯机器人公开发行A股股票&#xff0c;朋友圈都有谈论它的声音。那么小编就跟一跟风来给各位详细介绍一下目前科沃斯机器人首次公开发行A股股票的价格有关内容。希望下文能过给你们带来更多的收获哦。首次公开发行A股股票发行安排及初步询价公告保荐人(主承销商)&#x…

读书笔记:Information Architecture for the World Wide Web, 3rd Edition 北极熊 第一部分 1-3...

Introducing Information Architecture 信息架构简介 Chapter 1 Defining Information Architecture 信息架构的意义&#xff08;我们盖房子&#xff0c;之后&#xff0c;房子影响我们&#xff09; A DefinitionTablets, Scrolls, Books, and Libraries 石板、卷轴、书籍&#…

Mybatis执行流程分析_自定义简易Mybatis框架

自定义简易Mybatis框架 Mybatis执行流程分析 Mybatis代码编写流程: Mybatis配置文件加载过程: 需求分析及技术概述 根据上述的功能结构图, 得出如下需求: 1. 需要具有配置文件加载模块. 2. 支持使用构建者进行SessionFactory构建. 3. 支持使用工厂模式构建Session对象. 4.…

给大家推荐一个优质Linux内核技术公众号-Linux阅码场

作为一个Linux 技术公众号的作者&#xff0c;我觉得有义务推荐优秀的公众号&#xff0c;推广内容&#xff0c;希望对大家的学习有所帮助~Linux阅码场是一个专注Linux内核和系统编程与调试调优技术的公众号&#xff0c;它的文章云集了国内众多知名企业一线工程师的心得。无论你工…

图数据库_ONgDB图数据库与Spark的集成

快速探索图数据与图计算图计算是研究客观世界当中的任何事物和事物之间的关系&#xff0c;对其进行完整的刻划、计算和分析的一门技术。图计算依赖底于底层图数据模型&#xff0c;在图数据模型基础上计算分析Spark是一个非常流行且成熟稳定的计算引擎。下面文章从ONgDB与Spark的…

MyBatis动态SQL_多表查询_延迟加载_缓存

POJO包装传递对象 //POJO实体 public class QueryConditionObject {private User user;//user get,set方法 }//Dao 接口 public interface UserMapper{List<User> findByCondition(QueryConditionObject qco); }//UserMapper.xml中的select标签 <select id"find…

2019 高考填报志愿建议

2019 高考填报志愿建议1、城市很关键&#xff0c;在大城市上学和小地方上学会有很大的不同&#xff0c;现在很多毕业生毕业后会往北上广深跑&#xff0c;很多原因是因为这里的就业机会多&#xff0c;薪资比内地好太多了&#xff0c;如果你大学就能在这样的地方上学&#xff0c;…

纸机器人的折法_好神奇!他们竟用一张纸折成了一个机器人

一张纸&#xff0c;折成一只青蛙&#xff0c;或者一双腿、一条毛毛虫&#xff0c;装上一个电机&#xff0c;就能在桌子上爬行走动、蹦蹦跳跳。一群来自新加坡的大一学生&#xff0c;最近在浙江大学上了3星期的工业设计课&#xff0c;他们交出的作业就是外形多样且有着丰富运动形…

韦东山:闲鱼与盗版更配,起诉到底绝不和解!

之前很多人问&#xff0c;我和韦老师是什么关系&#xff0c;我们是本家人&#xff0c;至于更深的关系&#xff0c;我也不知道&#xff0c;这次事件受老师委托&#xff0c;帮忙发文支持&#xff0c;看到的朋友&#xff0c;也希望给予转发支持&#xff0c;感激不尽~大学的时候&am…

Windows下搭建FTP服务器

一、什么是ftp? FTP 是File Transfer Protocol&#xff08;文件传输协议&#xff09;的英文简称&#xff0c;而中文简称为“文传协议”。用于Internet上的控制文件的双向传输。同时&#xff0c;它也是一个应用程序&#xff08;Application&#xff09;。基于不同的操作系统有不…

Redis常见数据类型_Redis通用指令

Redis常见数据类型 redis本身就是一个Map结构, 所有数据都采用key:value的形式, redis中的数据类型指的是value的类型, key部分永远是字符串 string(类似Java String) string基本操作: set key value //存储数据 get key value //获取数据 del key value //删除数据 mset …

h3c交换机重启_h3c交换机重置命令_h3c交换机如何初始化

h3c交换机重置命令_h3c交换机如何初始化reset saved-configurationThe saved configuration file will be erased. Are you sure? [Y/N]: y // 提示是否擦除配置文件Configuration in the device is being cleared.Please wait ......Configurat…

我关注的学习公众号

在这个激烈竞争的社会&#xff0c;职场上还有“一招鲜”么&#xff1f;面对35岁的“魔咒”&#xff0c;提升自我的路很多&#xff0c;学习是其中最为捷径的一条。只有不断学习新知识&#xff0c;才能保持进步。今天为大家整理了8个公众号&#xff0c;分别为各个领域的佼佼者&am…

我对ThreadLocal的理解

声明&#xff1a;小弟菜狗一个。对ThreadLocal的描写叙述和理解难免有所偏差 近期由于须要深入的了解android的handler消息机制而去查看了Looper的源代码。众所周知在主线程中是不须要在程序猿在代码新建一个Looper对象的&#xff0c;由于在主线程创建时它就被创建出来了。所以…

如何让开关打开_安卓手机如何打开USB调试模式

点击上方“手机互联” 关注我吧&#xff01;什么是USB调试模式&#xff1f;USB调试模式是 安卓手机提供的一个用于开发工作的功能。使用该功能可在设备和安卓手机之间复制数据、在移动设备上安装应用程序、读取日志数据等等。默认情况下&#xff0c;USB 调试模式是关闭的&#…