通过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框架实现的更多相关文章

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

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

  2. Java实现简单的RPC框架(美团面试)

    一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...

  3. 学习写简单的RPC框架demo

    学习实现一个简单的RPC框架. 工程主要目录分级结构: rpc-common: 公共基础包,能力提供包 rpc-provider: 服务提供者 rpc-consumer:服务消费者 rpc-servi ...

  4. 徒手撸一个简单的RPC框架

    来源:https://juejin.im/post/5c4481a4f265da613438aec3 之前在牛逼哄哄的 RPC 框架,底层到底什么原理得知了RPC(远程过程调用)简单来说就是调用远程的 ...

  5. Java实现简单的RPC框架

    一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...

  6. Java 实现简单的RPC框架

    0 引言 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用).He ...

  7. Java 实现简单的 RPC 框架

    RPC 简介 RPC,全称为 Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式,而不需要了解底层网络技术 ...

  8. 动手实现一个简单的 rpc 框架到入门 grpc (上)

    rpc 全称 Remote Procedure Call 远程过程调用,即调用远程方法.我们调用当前进程中的方法时很简单,但是想要调用不同进程,甚至不同主机.不同语言中的方法时就需要借助 rpc 来实 ...

  9. 动手实现一个简单的 rpc 框架到入门 grpc (下)

    之前手动实现了一次简陋的 rpc 调用,为了简单使用了 json 编码信息,其实这是非常不可靠的,go 中 json 解析会有一些问题,比如整数会变成浮点数,而且 json 字符串比较占空间. gRP ...

随机推荐

  1. Install rapyuta client on Raspberry Pi

    Install rapyuta on client sudo git clone -b master https://github.com/cnsdytzy/-Rapyuta-installation ...

  2. Shrinking images on Linux

    When creating images from existing ISOs you often need to allocate a number of MB for the image to a ...

  3. 4.JAVA基础复习——JAVA中的构造函数与this关键字

    构造函数:构建创造对象时调用的函数 特点: 1.函数名与类名相同. 2.不用定义返回值类型. 3.没有具体的返回值. public class Demo { private int age; priv ...

  4. sai u 2016

    再过20分钟,我就要结束2016年的工作回家过春节了.真是难过的一天啊,从来没有今天那么感受深刻,那么嫌弃时间太慢,没有归家心似箭,没有近乡情怯,只是好想,呵呵,来个午睡,来场电影,来点小说,哈哈哈. ...

  5. TeamCity Agent安装

    1 docker安装 docker run -it -e SERVER_URL= \ -v /home/lishan/teamcity/conf:/data/teamcity_agent/conf \ ...

  6. Spring cloud Greenwich Eureka

    1.父工程POM文件中: <dependencyManagement> <dependencies> <!--spring cloud--> <depende ...

  7. io模型---非阻塞模型

    Linux下,可以通过设置socket使其变为non-blocking.当对一个non-blocking socket执行读操作时,流程是这个样子: 从图中可以看出,当用户进程发出read操作时,如果 ...

  8. 某大公司的sql面试题

    问:关系模式:User(userId, userName), Article(articleId, userId, title,   content),Vote(articleId, score),U ...

  9. 利用Java手写简单的httpserver

    前言: 在看完尚学堂JAVA300中讲解如何实现一个最简单的httpserver部分的视频之后, 一.前置知识 1.HTTP协议 当前互联网网页访问主要采用了B/S的模式,既一个浏览器,一个服务器,浏 ...

  10. 【配置】MongoDB配置文件详细配置

    # 数据文件位置 dbpath = /opt/module/mongoData # 日志文件位置 logpath = /opt/module/mongoLog/mongodb.log # 以追加方式写 ...