通过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. shell脚本中各类括号的作用(小结)

    技巧小结: 字符串比较用双中括号[[ ]]:算数比较用单中括号[ ]——左右留空格 算数运算用双小括号(( )) :shell命令及输出用小括号( )——左右不留空格 快速替换用花括号{ }——左右留 ...

  2. 功能比较全的StackExchange.Redis封装帮助类(.Net/C#)

    Redis官网https://redis.io/ 以下内容未全部验证,如有问题请指出 //static NewtonsoftSerializer serializer = new Newtonsoft ...

  3. x509证书相关内容

    什么是证书 X.509证书,其核心是根据RFC 5280编码或数字签名的数字文档.    实际上,术语X.509证书通常指的是IETF的PKIX证书和X.509 v3证书标准的CRL 文件,即如RFC ...

  4. 【转载】pycharm破解,可使用到2099年.pycharm版本 pycharm-professional-2016.3.1

    1. Pycharm的安装方法,论坛很多,这里就不赘述了.参照:http://blog.csdn.net/qq_29883591/article/details/52664478 2. 下载Pycha ...

  5. ssh很慢的问题转子

    根据网上的解决办法解决了,记录一下: 问题:ssh  ***@192.*.*.*  ,然后就一直卡在这个地方,很久以后才会出现让输入密码的提示 解决办法:1.关闭防火墙--chkconfig ipta ...

  6. SlidingMenu第二篇 --- SlidingMenu常用属性介绍

    /** * 设置滑动的屏幕范围 * 1. TOUCHMODE_MARGIN 设置为全屏边缘可滑动 * 2. TOUCHMODE_FULLSCREEN 设置为全屏区域都可以滑动 * 3. TOUCHMO ...

  7. 271. 杨老师的照相排列【线性DP】

    杨老师希望给他的班级拍一张合照. 学生们将站成左端对齐的多排,靠后的排站的人数不能少于靠前的排. 例如,12名学生(从后向前)可以排列成每排5,3,3,1人,如下所示: X X X X X X X X ...

  8. BZOJ-1721|线性dp-缆车支柱

    Ski Lift 缆车支柱 Description Farmer Ron in Colorado is building a ski resort for his cows (though budge ...

  9. 牛客练习赛43F Tachibana Kanade Loves Game

    题目地址 Link 题解 这题其实就是求1~n中有多少与2~20互质的数,然后其实只跟1~20里面的质数有关. 那么考虑容斥一下求出来一共有多少个不互质的,用n减一下就是互质的数的个数了.然后判一下a ...

  10. Pandorabox(Openwrt) 双宽带(WAN) 叠加网络实战

    准备 一台已经刷好Pandorabox(Openwrt)的路由器.两条宽带 实战环境 固件:PandoraBox R8.1.12 By Lean 硬件:K2P A1版 过程 配置VLAN 为了将一个L ...