RPC-基于原生java实现
一:什么是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实现的更多相关文章
- github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调
github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调.仅支持一个server和一个client交互. 地址:https://github.com/rocket049/ ...
- 分布式架构的基石.简单的 RPC 框架实现(JAVA)
前言 RPC 的全称是 Remote Procedure Call,它是一种进程间通信方式.允许像调用本地服务一样调用远程服务. 学习来源:<分布式系统架构:原理与实践> - 李林锋 1. ...
- 原生java调用webservice的方法,不用生成客户端代码
原生java调用webservice的方法,不用生成客户端代码 2015年10月29日 16:46:59 阅读数:1455 <span style="font-family: Aria ...
- 用jQuery基于原生js封装的轮播
我发现轮播在很多网站里面都用到过,一个绚丽的轮播可以为网页增色不少,最近闲来无事,也用原生js封装了一个轮播,可能不像网上的插件那么炫,但是也有用心去做.主要用了闭包的思想.需要传递的参数有:图片地址 ...
- 基于纯Java代码的Spring容器和Web容器零配置的思考和实现(3) - 使用配置
经过<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(1) - 数据源与事务管理>和<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(2) - ...
- 基于原生js的图片延迟加载
当页面图片比较多的时候,我们通常会做一个延迟加载,避免页面打开时一下子的请求数太多,加载过慢影响用户体验. 如果项目用了jquery框架,则可以直接用 jquery.lazyload.可在jquery ...
- 基于原生js的返回顶部组件,兼容主流浏览器
基于原生js的返回顶部插件,兼容IE8及以上.FF.chrome等主流浏览器. js文件中封装了getScrollTop()和changeScrollTop()函数分别用于获取滚动条滚动的高度和修改滚 ...
- 原生Java代码拷贝目录
拷贝.移动文件(夹),有三方包commons-io可以用,但是有时候有自己的需求,只能使用原生java代码,这时可以用以下几种方式进行拷贝: 1.使用系统命令(Linux)调用 此种方式对操作系统有要 ...
- 一个基于原生JavaScript开发的、轻量的验证码生成插件
Vcode.js 一个基于原生JavaScript开发的.轻量的验证码生成插件 V: 1.0.0 DEMO:https://jofunliang.github.io/Vcode.js/example. ...
- RPC基于http协议通过netty支持文件上传下载
本人在中间件研发组(主要开发RPC),近期遇到一个需求:RPC基于http协议通过netty支持文件上传下载 经过一系列的资料查找学习,终于实现了该功能 通过netty实现文件上传下载,主要在编解码时 ...
随机推荐
- MASM DEBUG LINKER免费下载
这资源全被CSDN霸占了,对于我这种不使用CSND的人,没积分,真TM不好找,搞个共享的. 网盘链接,永久有效 https://pan.baidu.com/s/1Ws5axrfos1cpWL9jyAE ...
- Nacos 快速开始
原文:https://nacos.io/zh-cn/docs/quick-start.html https://www.jianshu.com/p/16ff6d6db0cf Nacos安装: 1.从 ...
- apache-2.4.x 编译安装方法
apache-2.4.x 编译安装方法 作者:朱 茂海 /分类:Apache 字号:L M S apache-.2与新出的apache-.4安装不同的地方在于,.4版的已经不自带apr库,所以在安装a ...
- [原创]Laravel 基于redis队列的解析
目录 参考链接 本文环境 为什么使用队列 Laravel 中的队列 分发任务 任务队列 Worker Last-Modified: 2019年5月10日11:44:18 参考链接 使用 Laravel ...
- 【leetcode】Preimage Size of Factorial Zeroes Function
题目如下: 解题思路:<编程之美>中有一个章节是不要被阶乘吓倒,里面讲述了“问题一:给定一个整数N,那么N的阶乘末尾有多少个0呢?例如N = 10, N! = 362800,N! 的末尾有 ...
- css常用小知识点汇总(一)
1.文本过多溢出,怎么让他隐藏变成点点点(...)呢? text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-line- ...
- Java——面向对象编程
在面向对象的编程中,不能再有第一步.第二步怎么做的概念. [对象和类]
- [HG]walk 题解
前言 学长博客划水,抄题解,差评. 于是我来重新写一篇正常的题解,虽然解法跟标程不一样,但是复杂度是一样的. 题面 题目描述 在比特镇一共有\(n\)个街区,编号依次为\(1\)到\(n\),它们之间 ...
- Codeforces Round #579 (Div. 3) 套题 题解
A. Circle of Students 题目:https://codeforces.com/contest/1203/problem/A 题意:一堆人坐成一个环,问能否按逆时针或者顺时针 ...
- [CSP-S模拟测试]:大佬(kat)(数学期望)
题目描述 辣鸡$ljh\ NOI$之后就退役了,然后就滚去学文化课了.他发现$katarina$大佬真是太强了,于是就学习了一下$katarina$大佬的做题方法.比如这是一本有$n$道题的练习册,$ ...