自定义RPC框架--基于JAVA实现
视频教程地址 DT课堂(原名颜群)
整体思路
RPC(Remote Procedure Call),即远程过程调用。使用RPC,可以像使用本地的程序一样使用远程计算机上的程序。RPC使得开发分布式程序更加容易。下面是一个基于java的简单的RPC实例,有助于学习dubbo或grpc等框架的原理。
原理分析
RPC采用客户机/服务器模式。请求程序就是客户端,而服务提供程序就是服务端。也就是说需要两个角色,服务端和客户端。首先,客户端调用进程发送一个调用信息(调用的接口,方法名,方法传入参数等)给服务端,然后等待应答信息。在服务器端,当一个调用信息到达,服务器获得调用信息并解析执行调用的接口和方法,然后发送调用的方法返回值,然后等待下一个调用信息,最后,客户端接收到服务端发送回来的方法返回信息。
以下是代码
服务端
首先需要业务类,然后需要一个注册中心,注册中心可以把被调用的业务类注册到一个map集合中,然后根据客户端发送过来的调用信息执行相应的业务类对象的方法,并返回方法的返回值
创建需要发布的业务类接口和具体实现类
- package org.rpc.service;
- public interface HelloService {
- Object sayHello(String name);
- }
- package org.rpc.service;
- public class HelloServiceImpl implements HelloService {
- public Object sayHello(String name) {
- // TODO Auto-generated method stub
- return "hello,"+name;
- }
- }
然后是服务端的主体类,就是注册中心。定义三个方法start()初始化方法,stop()停止服务方法,register()注册中心
- package org.rpc.service;
- public interface Server {
- void start();
- void stop();
- void register(Class service,Class serviceImpl);
- }
具体实现类,首先声明一个map集合来来存放业务类,key是业务类的接口名,value是接口对应的具体实现类class对象
- package org.rpc.service;
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- import java.lang.reflect.Method;
- import java.net.InetSocketAddress;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.HashMap;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class ServerCenter implements Server {
- private static HashMap<String, Class> serviceRegister=new HashMap<>();
- private static int PORT=0;
- //根据本地计算机性能生成对应容量的线程池
- private static ExecutorService servicePool=
- Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
- public ServerCenter() {
- }
- public ServerCenter(int port) {
- this.PORT=port;
- }
- @Override
- public void start() {
- ServerSocket server=null;
- try {
- server=new ServerSocket();
- server.bind(new InetSocketAddress(PORT));
- } catch (IOException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- while(true) {
- System.out.println("等待客户端连接...");
- Socket socket = null;
- try {
- //服务器等待连接,每当有客户端连接就开启线程执行调用信息处理类
- socket = server.accept();
- servicePool.execute(new ServiceTask(socket));
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- @Override
- public void stop() {
- servicePool.shutdown();
- }
- @Override
- public void register(Class service, Class serviceImpl) {
- serviceRegister.put(service.getName(), serviceImpl);
- }
- //具体调用信息处理类,解析客户端发来的调用信息并执行对应的业务方法并相应方法的返回值
- private class ServiceTask implements Runnable{
- private Socket socket=null;
- public ServiceTask() {
- }
- public ServiceTask(Socket socket) {
- this.socket = socket;
- }
- @Override
- public void run() {
- ObjectInputStream ois=null;
- ObjectOutputStream oos=null;
- try {
- System.out.println("客户端已连接");
- ois=new ObjectInputStream(socket.getInputStream());
- //获取客户端发来的接口名
- String className=ois.readUTF();
- //获取客户端发来的方法
- String methodName=ois.readUTF();
- //获取客户端发来的方法参数类型
- Class[] methodTypes=(Class[]) ois.readObject();
- //获取客户端发来的方法参数值
- Object[] args =(Object[]) ois.readObject();
- //从map中找到需要的接口并执行客户端调用的方法
- Class service=serviceRegister.get(className);
- Method method = service.getMethod(methodName,methodTypes);
- Object returns = method.invoke(service.newInstance(), args);
- oos=new ObjectOutputStream(socket.getOutputStream());
- //返回方法执行的结果
- oos.writeObject(returns);
- }catch (Exception e) {
- e.printStackTrace();
- }finally {
- try {
- //关闭资源
- if(oos!=null)oos.close();
- if(ois!=null)ois.close();
- if(socket!=null)socket.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
- }
客户端
客户端使用动态代理来接受服务端的业务类返回值
- package org.rpc.client;
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- import java.net.InetSocketAddress;
- import java.net.Socket;
- public class Client {
- @SuppressWarnings("unchecked")
- public static <T> T getRemoteProxyObj(Class serviceInterface,InetSocketAddress addr) {
- return (T)Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[] {serviceInterface},
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args){
- Socket socket =null;
- ObjectInputStream ois=null;
- ObjectOutputStream oos=null;
- Object result=null;
- try {
- socket=new Socket();
- socket.connect(addr);
- oos=new ObjectOutputStream(socket.getOutputStream());
- //发送需要的接口名
- oos.writeUTF(serviceInterface.getName());
- //发送需要的方法名
- oos.writeUTF(method.getName());
- //方法参数类型
- oos.writeObject(method.getParameterTypes());
- //方法参数
- oos.writeObject(args);
- ois=new ObjectInputStream(socket.getInputStream());
- result=ois.readObject();
- }catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- if(oos!=null)oos.close();
- if(ois!=null)ois.close();
- if(socket!=null)socket.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- return result;
- }
- });
- }
- }
测试
服务端使用register()方法对HelloService类进行注册并开启服务等待客户端连接
- package org.rpc.test;
- import org.rpc.service.HelloService;
- import org.rpc.service.HelloServiceImpl;
- import org.rpc.service.Server;
- import org.rpc.service.ServerCenter;
- public class ServerTest {
- public static void main(String[] args) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- Server server = new ServerCenter(9999);
- server.register(HelloService.class, HelloServiceImpl.class);
- server.start();
- }
- }).start();
- }
- }
客户端直接声明需要调用的业务类的接口接受动态代理对象并执行需要的方法
- package org.rpc.test;
- import java.net.InetSocketAddress;
- import org.rpc.client.Client;
- import org.rpc.service.HelloService;
- public class ClientTest {
- public static void main(String[] args) throws ClassNotFoundException {
- HelloService hs=Client.getRemoteProxyObj(Class.forName("org.rpc.service.HelloService"), new InetSocketAddress("127.0.0.1", 9999));
- System.out.println(hs.sayHello("world"));
- }
- }
视频教程地址http://aibd.ke.qq.com
自定义RPC框架--基于JAVA实现的更多相关文章
- 手写简易版RPC框架基于Socket
什么是RPC框架? RPC就是远程调用过程,实现各个服务间的通信,像调用本地服务一样. RPC有什么优点? - 提高服务的拓展性,解耦.- 开发人员可以针对模块开发,互不影响.- 提升系统的可维护性及 ...
- 简单RPC框架-基于Consul的服务注册与发现
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- 分布式架构的基石.简单的 RPC 框架实现(JAVA)
前言 RPC 的全称是 Remote Procedure Call,它是一种进程间通信方式.允许像调用本地服务一样调用远程服务. 学习来源:<分布式系统架构:原理与实践> - 李林锋 1. ...
- GRPC 1.3.4 发布,Google 高性能 RPC 框架(Java C++ Go)
GRPC 1.3.4 发布了,GRPC 是一个高性能.开源.通用的 RPC 框架,面向移动和 HTTP/2 设计,是由谷歌发布的首款基于 Protocol Buffers 的 RPC 框架. GRPC ...
- 完全开源Android网络框架 — 基于JAVA原生的HTTP框架
HttpNet网络请求框架基于HttpUrlConnection,采用Client + Request + Call的请求模型,支持https默认证书,数字安全证书.支持http代理!后续将会实现队列 ...
- 分布式架构探索 - 1. RPC框架之Java原生RMI
1. 什么是RPC RPC(Remote Procedure Call)即远程过程调用,指的是不同机器间系统方法的调用,这和 同机器动态链接库(DLL)有点类似,只不过RPC是不同机器,通过网络通信来 ...
- 遗传算法框架-基于java jenetics库实现
本篇并非介绍如何从0开始开发遗传算法框架,反而推荐各位使用已有的GA库jenetics来做遗传算法. GA算法的逻辑还是贴下: 好了,下面介绍的是基于jenetics开发的更贴近业务侧的框架,以及使用 ...
- 【原创】三分钟教你学会MVC框架——基于java web开发(2)
没想到我的上一篇博客有这么多人看,还有几位看完之后给我留言加油,不胜感激,备受鼓励,啥都别说了,继续系列文章之第二篇.(如果没看过我第一篇博客的朋友,可以到我的主页上先浏览完再看这篇文章,以免上下文对 ...
- 【原创】三分钟教你学会MVC框架——基于java web开发(1)
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用于组织代码用一种业务逻辑和数据显示分离的方法. ...
随机推荐
- python, generator.next()和send()
对于普通的生成器,第一个next调用,相当于启动生成器,会从生成器函数的第一行代码开始执行,直到第一次执行完yield语句(第4行)后,跳出生成器函数. 然后第二个next调用,进入生成器函数后,从y ...
- “数据上帝” Jeff Hammerbacher
出生于1983年的数学天才Jeff Hammerbacher在23岁时加入了Facebook,一手组建起数据分析队伍.他是“数据科学”(data science)一词的提出者之一,被人们称为“数据上帝 ...
- [zz] 拍照需谨慎:20张错位照片让人笑喷
http://www.kaixin001.com/qiushi/repaste/105876543_10386791939.html?uid=130103872&urpid=103957489 ...
- vscode编辑Markdown时的贴图工具
参看 https://www.jianshu.com/p/74b960efb697 说明: 1. 文件-->首选项-->设置-->填入paste,设置Path值为 ${current ...
- 安装JVCL/JCL组件
在安装的时候,注意要先安装JCL,我试图直接安装JVCL,提示找不到文件,先安装JCL后再安装就不存在这个问题.安装到组件面板上的安装包以D结尾,可以Install,以R结尾的只要编译就可以了. 安装 ...
- [转][C#]程序的动态编译
转自:https://blog.csdn.net/clb929/article/details/51385399 附 文件下载
- Faster R-CNN代码例子
主要参考文章:1,从编程实现角度学习Faster R-CNN(附极简实现) 经常是做到一半发现收敛情况不理想,然后又回去看看这篇文章的细节. 另外两篇: 2,Faster R-CNN学习总结 ...
- flutter学习地址
Flutter - 不一样的跨平台解决方案: 关于Flutter,你想知道的都在这里了!: Flutter 时间表 2015 年 4 月,Flutter(最初代号 Sky)在 Dart Devel ...
- 高性能mysql 第六章查询性能优化 总结(上)查询的执行过程
6 查询性能优化 6.1为什么查询会变慢 这里说明了的查询执行周期,从客户端到服务器端,服务器端解析,优化器生成执行计划,执行(可以细分,大体过程可以通过show profile查看),从服务器端返 ...
- XML和实体类之间相互转换(序列化和反序列化)
我们需要在XML与实体类,DataTable,List之间进行转换,下面是XmlUtil类,该类来自网络并稍加修改. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...