视频教程地址 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实现的更多相关文章

  1. 手写简易版RPC框架基于Socket

    什么是RPC框架? RPC就是远程调用过程,实现各个服务间的通信,像调用本地服务一样. RPC有什么优点? - 提高服务的拓展性,解耦.- 开发人员可以针对模块开发,互不影响.- 提升系统的可维护性及 ...

  2. 简单RPC框架-基于Consul的服务注册与发现

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  3. 分布式架构的基石.简单的 RPC 框架实现(JAVA)

    前言 RPC 的全称是 Remote Procedure Call,它是一种进程间通信方式.允许像调用本地服务一样调用远程服务. 学习来源:<分布式系统架构:原理与实践> - 李林锋 1. ...

  4. GRPC 1.3.4 发布,Google 高性能 RPC 框架(Java C++ Go)

    GRPC 1.3.4 发布了,GRPC 是一个高性能.开源.通用的 RPC 框架,面向移动和 HTTP/2 设计,是由谷歌发布的首款基于 Protocol Buffers 的 RPC 框架. GRPC ...

  5. 完全开源Android网络框架 — 基于JAVA原生的HTTP框架

    HttpNet网络请求框架基于HttpUrlConnection,采用Client + Request + Call的请求模型,支持https默认证书,数字安全证书.支持http代理!后续将会实现队列 ...

  6. 分布式架构探索 - 1. RPC框架之Java原生RMI

    1. 什么是RPC RPC(Remote Procedure Call)即远程过程调用,指的是不同机器间系统方法的调用,这和 同机器动态链接库(DLL)有点类似,只不过RPC是不同机器,通过网络通信来 ...

  7. 遗传算法框架-基于java jenetics库实现

    本篇并非介绍如何从0开始开发遗传算法框架,反而推荐各位使用已有的GA库jenetics来做遗传算法. GA算法的逻辑还是贴下: 好了,下面介绍的是基于jenetics开发的更贴近业务侧的框架,以及使用 ...

  8. 【原创】三分钟教你学会MVC框架——基于java web开发(2)

    没想到我的上一篇博客有这么多人看,还有几位看完之后给我留言加油,不胜感激,备受鼓励,啥都别说了,继续系列文章之第二篇.(如果没看过我第一篇博客的朋友,可以到我的主页上先浏览完再看这篇文章,以免上下文对 ...

  9. 【原创】三分钟教你学会MVC框架——基于java web开发(1)

    MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用于组织代码用一种业务逻辑和数据显示分离的方法. ...

随机推荐

  1. 以Windows服务方式运行ASP.NET Core程序【转载】

    我们对ASP.NET Core的使用已经进行了相当一段时间了,大多数时候,我们的Web程序都是发布到Linux主机上的,当然了,偶尔也有需求要发布到Windows主机上,这样问题就来了,难道直接以控制 ...

  2. postgreSQL数据库limit分页、排序

    postgreSQL数据库limit分页.排序 语法: select * from persons limit  A  offset  B; 解释: A就是你需要多少行: B就是查询的起点位置. 示例 ...

  3. MySQL Point in Time Recovery the Right Way

    In this blog, I’ll look at how to do MySQL point in time recovery (PITR) correctly. Sometimes we nee ...

  4. forward reference前向引用,gloal values and local values全局变量和局部变量,recursive function递归函数

    1.全局变量与局部变量练习 1 # -*- coding: UTF-8 -*- 2 def bar(): 3 print('from bar') 4 def foo(): 5 print('from ...

  5. sql server紧急状态下登录脚本

    --打开xp_cmdshell功能  EXEC [sys].[sp_configure] @configname = 'xp_cmdshell', -- varchar(35)    @configv ...

  6. Struts1 不能进入Action,页面空白问题解决

    http://blog.csdn.net/barry_liao/article/details/35592935 Struts1 不能进入Action,页面空白问题解决 标签: Struts1Acti ...

  7. Linux下usb设备驱动详解

    USB驱动分为两块,一块是USB的bus驱动,这个东西,Linux内核已经做好了,我们可以不管,我们只需要了解它的功能.形象的说,USB的bus驱动相当于铺出一条路来,让所有的信息都可以通过这条USB ...

  8. redux & react-redux

    在vue中,可以使用vuex进行数据管理,在react中,可以使用redux进行数据管理.redux主要由Store.Reducer和Action组成: Store:状态载体,访问状态.提交状态.监听 ...

  9. 基础 - 字符读取函数scanf、getchar、gets、cin(清空缓存区解决单字符回车问题)

    0x01 scanf.getchar.cin读取单字符: 如下: //scanf读取字符 回车问题 void Sub_1_1() { char v1,v2; scanf("%c", ...

  10. 铁板纹理 铁锈Rust

    软件:Substance Designer 2017.1.2 这篇文章记录铁锈的制作方法,铁锈效果见图一 图一:铁锈Rust 铁锈的具体制作过程为: 使用BnW Spots 2(Noise)结点生成噪 ...