最简单的RPC框架实现
通过java原生的序列化,Socket通信,动态代理和反射机制,实现一个简单的RPC框架,由三部分组成:
1、服务提供者,运行再服务端,负责提供服务接口定义和服务实现类
2、服务发布者,运行再RPC服务端,负责将本地服务发布成远程服务,供其他消费者调用
3、本地服务代理,运行再RPC客户端,通过代理调用远程服务提供者,然后将结果进行封装返回给本地消费者
服务端接口定义和实现,如下:
代码清单 1-1 接口定义
public interface EchoService {
String echo(String ping);
}
代码清单1-2
public class EchoServiceImpl implements EchoService {
public String echo(String ping) {
return ping != null ? ping + " -- I am ok." : "I am ok";
}
}
代码清单1-3
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.concurrent.Executor;
import java.util.concurrent.Executors; /**
*
*/
public class RpcExporter {
static Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public static void exporter(String hostName , int port) throws Exception{
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(hostName,port));
try {
while (true){
executor.execute(new ExporterTask(serverSocket.accept()));
}
}finally {
serverSocket.close();
}
} private static class ExporterTask implements Runnable{
Socket client = null; public ExporterTask(Socket client) {
this.client = client;
} public void run() {
ObjectInputStream inputStream = null;
ObjectOutputStream outputStream = null;
try {
inputStream = new ObjectInputStream(client.getInputStream());
String interfaceName = inputStream.readUTF();
Class<?> service = Class.forName(interfaceName);
String methodName = inputStream.readUTF();
Class<?> [] parameterTypes = (Class<?> [])inputStream.readObject();
Object [] arguments = (Object [])inputStream.readObject();
Method method = service.getMethod(methodName,parameterTypes);
Object result = method.invoke(service.newInstance(),arguments);
outputStream = new ObjectOutputStream(client.getOutputStream());
outputStream.writeObject(result); }catch (Exception e){
e.printStackTrace();
}finally {
if(outputStream != null){
try {
outputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
if(inputStream != null){
try {
inputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
if(client != null){
try {
client.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
}
服务发布者的主要职责如下:
1、作为服务端,监控客户端的TCP连接,接收到新的客户端连接之后,将其封装成Task,由线程池执行
2、将客户端发送的码流反序列化成对象,反射调用实现者,获取执行结果
3、将执行结果对象序列化,通过socket发送给客户端
4、远程服务调用完成之后,释放Socket等连接字段,防止句柄泄露
RPC客户端本地服务代理源码如下:
代码清单1-4
package com.habit; import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory; 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 RpcImporter<S> { public S importer(final Class<?> serviceClass, final InetSocketAddress address) {
return (S) Proxy.newProxyInstance(serviceClass.getClassLoader(), new Class<?>[]{serviceClass.getInterfaces()[0]},
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = null;
ObjectOutputStream outputStream = null;
ObjectInputStream inputStream = null;
try {
socket = new Socket();
socket.connect(address);
outputStream = new ObjectOutputStream(socket.getOutputStream());
outputStream.writeUTF(serviceClass.getName());
outputStream.writeUTF(method.getName());
outputStream.writeObject(method.getParameterTypes());
outputStream.writeObject(args);
inputStream = new ObjectInputStream(socket.getInputStream());
return inputStream.readObject(); } finally {
if (socket != null) {
socket.close();
}
if (outputStream != null) {
outputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
}
}
}); }
}
本地服务代理的主要功能:
1、将本地的接口调用转成JDK的动态代理,再动态代理中实现接口的远程调用
2、创建Socket客户端,根据指定地址链接远程服务提供者
3、将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者
4、同步阻塞等待服务端返回应答,获取应答之后返回
测试代码:
代码清单1-5
package com.habit; import java.net.InetSocketAddress; /**
*
*/
public class RpcTest {
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
try {
RpcExporter.exporter("localhost",8088);
}catch (Exception e){
e.printStackTrace();
}
}
}).start(); RpcImporter<EchoService> importer = new RpcImporter<EchoService>();
EchoService echo = importer.importer(EchoServiceImpl.class,new InetSocketAddress("localhost",8088));
System.out.println(echo.echo("Are you ok?"));
}
}
创建一个异步发布服务端的线程并启动,用于接口rpc客户端的请求,根据请求参数调用服务实现类,返回结果给客户端
随后,创建客户端服务代理类,构建rpc请求参数,发起rpc请求,将调用结果输出到控制台,执行结果如下:
Are you ok? -- I am ok.
最简单的RPC框架实现的更多相关文章
- 分布式架构的基石.简单的 RPC 框架实现(JAVA)
前言 RPC 的全称是 Remote Procedure Call,它是一种进程间通信方式.允许像调用本地服务一样调用远程服务. 学习来源:<分布式系统架构:原理与实践> - 李林锋 1. ...
- Java实现简单的RPC框架(美团面试)
一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...
- 学习写简单的RPC框架demo
学习实现一个简单的RPC框架. 工程主要目录分级结构: rpc-common: 公共基础包,能力提供包 rpc-provider: 服务提供者 rpc-consumer:服务消费者 rpc-servi ...
- 徒手撸一个简单的RPC框架
来源:https://juejin.im/post/5c4481a4f265da613438aec3 之前在牛逼哄哄的 RPC 框架,底层到底什么原理得知了RPC(远程过程调用)简单来说就是调用远程的 ...
- Java实现简单的RPC框架
一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...
- Java 实现简单的RPC框架
0 引言 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用).He ...
- Java 实现简单的 RPC 框架
RPC 简介 RPC,全称为 Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式,而不需要了解底层网络技术 ...
- 动手实现一个简单的 rpc 框架到入门 grpc (上)
rpc 全称 Remote Procedure Call 远程过程调用,即调用远程方法.我们调用当前进程中的方法时很简单,但是想要调用不同进程,甚至不同主机.不同语言中的方法时就需要借助 rpc 来实 ...
- 动手实现一个简单的 rpc 框架到入门 grpc (下)
之前手动实现了一次简陋的 rpc 调用,为了简单使用了 json 编码信息,其实这是非常不可靠的,go 中 json 解析会有一些问题,比如整数会变成浮点数,而且 json 字符串比较占空间. gRP ...
随机推荐
- 2019春下载的sublime text都无法自动安装package control:解决办法
之前电脑的原因卸载了,于是重新安装sublime text3. 发现问题了.Package Control无法自动安装. 于是一通常用操作. 1.copy 安装码(你知道的)到control安装,失败 ...
- 整理的Python零基础入门!转载他人的!
安装Python 前往 官网下载 对应平台对应工具.另外Python2.7版本和3.3版本并不兼容,所以开发时请注意使用Python的版本. 作为Mac OS X使用者,其实更推荐 PyCharm I ...
- PKCS RSA执行标准
RSA是一种算法,但是,在相关应用的时候,还是需要有一些标准的.这就是pkcs.现在的各种程序中,基本都是遵循这个标准来使用RSA的.最近陆续读取RSA相关的内容进行学习. RSA官网:https:/ ...
- 编程规范(初尝ES6与webpack)
//针对ES6规范(第1-5条)start1.块级作用域let/const取代var:在let和const之间,建议优先使用const,尤其是在全局环境,不应该设置变量,只应设置常量. 2.解构赋值1 ...
- linux 查看CPU、内存、磁盘信息命令
[1]查看CPU信息 (1)查看CPU信息(型号) cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c (2)查看物理CPU个数 cat /pr ...
- my work
Dad, what's your first job? How did you achieved?
- opencv学习之路(40)、人脸识别算法——EigenFace、FisherFace、LBPH
一.人脸识别算法之特征脸方法(Eigenface) 1.原理介绍及数据收集 特征脸方法主要是基于PCA降维实现. 详细介绍和主要思想可以参考 http://blog.csdn.net/u0100066 ...
- OpenCV自带dnn的Example研究(2)— colorization
这个博客系列,简单来说,今天我们就是要研究 6个文件,看看在最新的OpenCV中,它们是如何发挥作用的. 在配置使用的过程中,需要注意使用较高版本的VS避免编译器兼容问题:由于DNN程序的运行依赖于训 ...
- POI中excle样式怎么写
POI中可能会用到一些需要设置EXCEL单元格格式的操作小结: 先获取工作薄对象: HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb ...
- 什么是MTBF测试【转】
本文转载自:https://blog.csdn.net/liuhaoemail/article/details/50531489 MTBF测试 目前,终端侧的可靠性测试基本上是采用称为”MTBF测试” ...