最简单的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 ...
随机推荐
- Install rapyuta client on Raspberry Pi
Install rapyuta on client sudo git clone -b master https://github.com/cnsdytzy/-Rapyuta-installation ...
- Shrinking images on Linux
When creating images from existing ISOs you often need to allocate a number of MB for the image to a ...
- 4.JAVA基础复习——JAVA中的构造函数与this关键字
构造函数:构建创造对象时调用的函数 特点: 1.函数名与类名相同. 2.不用定义返回值类型. 3.没有具体的返回值. public class Demo { private int age; priv ...
- sai u 2016
再过20分钟,我就要结束2016年的工作回家过春节了.真是难过的一天啊,从来没有今天那么感受深刻,那么嫌弃时间太慢,没有归家心似箭,没有近乡情怯,只是好想,呵呵,来个午睡,来场电影,来点小说,哈哈哈. ...
- TeamCity Agent安装
1 docker安装 docker run -it -e SERVER_URL= \ -v /home/lishan/teamcity/conf:/data/teamcity_agent/conf \ ...
- Spring cloud Greenwich Eureka
1.父工程POM文件中: <dependencyManagement> <dependencies> <!--spring cloud--> <depende ...
- io模型---非阻塞模型
Linux下,可以通过设置socket使其变为non-blocking.当对一个non-blocking socket执行读操作时,流程是这个样子: 从图中可以看出,当用户进程发出read操作时,如果 ...
- 某大公司的sql面试题
问:关系模式:User(userId, userName), Article(articleId, userId, title, content),Vote(articleId, score),U ...
- 利用Java手写简单的httpserver
前言: 在看完尚学堂JAVA300中讲解如何实现一个最简单的httpserver部分的视频之后, 一.前置知识 1.HTTP协议 当前互联网网页访问主要采用了B/S的模式,既一个浏览器,一个服务器,浏 ...
- 【配置】MongoDB配置文件详细配置
# 数据文件位置 dbpath = /opt/module/mongoData # 日志文件位置 logpath = /opt/module/mongoLog/mongodb.log # 以追加方式写 ...