一:什么是RPC

远程过程调用(Remote Procedure Call)。就是调用其他业务方的方法的时候,就像是调用自己本地的方法一样。

二:java rpc实现简介

服务端(使用反射)

(1)服务端写一个接口和一个接口的实现。

(2)服务端维护一个map,key为接口的类名,value为接口的实现类。

(3)服务端通过 ServerSocket 接收客户端发送过来的数据(接口的类名,方法名,请求参数)

(4)服务端根据接口的类名和方法名得到对应实现类的方法,通过反射调用服务

(5)把处理之后的结果通过 ServerSocket  返回给客户端

客户端(动态代理)

(1)把服务端的接口copy过来

(2)写一个代理类,调用服务端方法的时候,通过代理类的 invoke 方法把服务需要的 接口类名,方法名,请求参数 通过 Socket 发送给服务端;接收服务端处理的结果

三:具体实现的代码

(1)服务端的接口声明

public interface IHello {
String sayHello(String string);
}

(2)服务端接口的实现(真正干活的类)

public class HelloServiceImpl implements IHello{

	@Override
public String sayHello(String string) {
// TODO Auto-generated method stub
return "你好:" + string;
}
}

(3)服务端的服务类

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; public class RpcServer { private static final HashMap<String, Class<?>> serviceRegistry = new HashMap<>();
private int port; public RpcServer(int port) {
this.port =port;
} public RpcServer register(Class serviceInterface, Class impl) {
serviceRegistry.put(serviceInterface.getName(), impl);
return this;
} public void run() throws IOException { ServerSocket server = new ServerSocket();
server.bind(new InetSocketAddress (port));
System.out.println("start server");
ObjectInputStream input =null;
ObjectOutputStream output =null;
Socket socket=null;
try {
while(true){
socket = server.accept ();
input =new ObjectInputStream(socket.getInputStream());
String serviceName = input.readUTF();
String methodName = input.readUTF();
System.out.println ("客户端调用了 " + methodName + "方法");
Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
Object[] arguments = (Object[]) input.readObject();
Class serviceClass = serviceRegistry.get(serviceName);
if (serviceClass == null) {
throw new ClassNotFoundException(serviceName + " not found");
}
Method method = serviceClass.getMethod(methodName, parameterTypes);
Object result = method.invoke(serviceClass.newInstance(), arguments);
output = new ObjectOutputStream (socket.getOutputStream());
output.writeObject(result);
}
} catch (Exception e){
e.printStackTrace();
}
} public static void main(String[] args) throws IOException {
new RpcServer (8888).register(IHello.class,HelloServiceImpl.class).run();
} }

(4)客户端的实现

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; import com.cs.rpc.nativ.server.IHello; public class RpcClientProxy<T> implements InvocationHandler { private Class<T> serviceInterface;//被调用者的接口声明
private InetSocketAddress addr;//被调用者的地址(ip+port) public RpcClientProxy(Class<T> serviceInterface, String ip,String port) {
this.serviceInterface = serviceInterface;
this.addr = new InetSocketAddress(ip, Integer.parseInt ( port ));
} public T getClientIntance(){
return (T) Proxy.newProxyInstance (serviceInterface.getClassLoader(),new Class<?>[]{serviceInterface},this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = null;
ObjectOutputStream output = null;
ObjectInputStream input = null; try {
// 2.创建Socket客户端,根据指定地址连接远程服务提供者
socket = new Socket();
socket.connect(addr); // 3.将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者
output = new ObjectOutputStream(socket.getOutputStream());
output.writeUTF(serviceInterface.getName());
output.writeUTF(method.getName());
output.writeObject(method.getParameterTypes());
output.writeObject(args); // 4.同步阻塞等待服务器返回应答,获取应答后返回
input = new ObjectInputStream(socket.getInputStream());
return input.readObject();
} finally {
if (socket != null) socket.close();
if (output != null) output.close();
if (input != null) input.close();
}
} public static void main(String[] args) {
RpcClientProxy client = new RpcClientProxy<>(IHello.class,"localhost","8888");
IHello hello = (IHello) client.getClientIntance ();
System.out.println (hello.sayHello ( "socket rpc" ));
}
}

  

RPC-基于原生java实现的更多相关文章

  1. github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调

    github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调.仅支持一个server和一个client交互. 地址:https://github.com/rocket049/ ...

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

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

  3. 原生java调用webservice的方法,不用生成客户端代码

    原生java调用webservice的方法,不用生成客户端代码 2015年10月29日 16:46:59 阅读数:1455 <span style="font-family: Aria ...

  4. 用jQuery基于原生js封装的轮播

    我发现轮播在很多网站里面都用到过,一个绚丽的轮播可以为网页增色不少,最近闲来无事,也用原生js封装了一个轮播,可能不像网上的插件那么炫,但是也有用心去做.主要用了闭包的思想.需要传递的参数有:图片地址 ...

  5. 基于纯Java代码的Spring容器和Web容器零配置的思考和实现(3) - 使用配置

    经过<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(1) - 数据源与事务管理>和<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(2) - ...

  6. 基于原生js的图片延迟加载

    当页面图片比较多的时候,我们通常会做一个延迟加载,避免页面打开时一下子的请求数太多,加载过慢影响用户体验. 如果项目用了jquery框架,则可以直接用 jquery.lazyload.可在jquery ...

  7. 基于原生js的返回顶部组件,兼容主流浏览器

    基于原生js的返回顶部插件,兼容IE8及以上.FF.chrome等主流浏览器. js文件中封装了getScrollTop()和changeScrollTop()函数分别用于获取滚动条滚动的高度和修改滚 ...

  8. 原生Java代码拷贝目录

    拷贝.移动文件(夹),有三方包commons-io可以用,但是有时候有自己的需求,只能使用原生java代码,这时可以用以下几种方式进行拷贝: 1.使用系统命令(Linux)调用 此种方式对操作系统有要 ...

  9. 一个基于原生JavaScript开发的、轻量的验证码生成插件

    Vcode.js 一个基于原生JavaScript开发的.轻量的验证码生成插件 V: 1.0.0 DEMO:https://jofunliang.github.io/Vcode.js/example. ...

  10. RPC基于http协议通过netty支持文件上传下载

    本人在中间件研发组(主要开发RPC),近期遇到一个需求:RPC基于http协议通过netty支持文件上传下载 经过一系列的资料查找学习,终于实现了该功能 通过netty实现文件上传下载,主要在编解码时 ...

随机推荐

  1. git概述(三)

    Bug分支: 当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交: 并不是你不想提交,而是工作只进行 ...

  2. js学习之BOM和DOM

    1. 浏览器的原理 1.1 浏览器的多线程 (1)  解析js引擎线程 (2)  UI渲染线程 (3)  事件发起线程 (4)  发起请求的线程 (5)  定时器的线程 1.2 同步异步 (1)  前 ...

  3. [REPRINT]Properties vs. Getters and Setters

    http://www.python-course.eu/python3_properties.php Our new class means breaking the interface. The a ...

  4. 去掉html中的标签

    //去掉html中的图片 String regEx_image = "(<img.*src\\s*=\\s*(.*?)[^>]*?>)"; Pattern p_s ...

  5. 【leetcode】299. Bulls and Cows

    题目如下: 解题思路:本题难度不太大,对时间复杂度也没有很高的要求.我的做法是用一个字典来保存每个字符出现的次数,用正数1记录标记secret中出现的字符,用负数1记录guess中出现的字符,这样每出 ...

  6. iOS - 图片的显示模式

  7. SpringBoot搭建基于Spring+SpringMvc+Mybatis的REST服务

    Maven Plugin管理 通常,让你的Maven POM文件继承 spring-boot-starter-parent,并声明一个或多个 Starter POMs依赖即可. spring-boot ...

  8. CF D. Labyrinth 01BFS

    由于上下走不限制,所以按照贪心,我们应该尽可能走上下方向. 我们可以开一个双端队列,并认为每次提取队首的时候得到的是到达该点的最优策略.(这个一定是唯一的,因为不可能向右走几格,然后再退回去. ) 那 ...

  9. 【PowerOJ1742&网络流24题】试题库问题(最大流)

    题意: 思路: [问题分析] 二分图多重匹配问题,用最大流解决. [建模方法] 建立二分图,每个类别为X集合中的顶点,每个题为Y集合中的顶点,增设附加源S和汇T. 1.从S向每个Xi连接一条容量为该类 ...

  10. Java数据结构之单链表

    这篇文章主要讲解了通过java实现单链表的操作,一般我们开始学习链表的时候,都是使用C语言,C语言中我们可以通过结构体来定义节点,但是在Java中,我们没有结构体,我们使用的是通过类来定义我们所需要的 ...