- 浏览: 209052 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
sky88088:
感谢分享~
自定义的RPC的Java实现 -
a2773945:
好东西,谢谢大哥
自定义的RPC的Java实现 -
beer2008cn:
写的很棒
自定义的RPC的Java实现 -
shuangjue:
不能跨平台,和RMI相比有何优势呢?能否提供个跨平台的方案,比 ...
自定义的RPC的Java实现 -
god333666:
写得很不错 受启发
自定义的RPC的Java实现
在看hadoop的源代码的时候,看到hadoop实现了一个自定义的RPC,于是有了自己写代码实现RPC的想法。
RPC的全名Remote Process Call,即远程过程调用。使用RPC,可以像使用本地的程序一样使用远程服务器上的程序。下面是一个简单的RPC 调用实例,从中可以看到RPC如何使用以及好处:
public class MainClient { public static void main(String[] args) { Echo echo = RPC.getProxy(Echo.class, "127.0.0.1", 20382); System.out.println(echo.echo("hello,hello")); } }
public interface Echo { public String echo(String string); }
使用RPC.getProxy生成接口Echo的代理实现类。然后就可以像使用本地的程序一样来调用Echo中的echo方法。
使用RPC的好处是简化了远程服务访问。提高了开发效率。在分发代码时,只需要将接口分发给客户端使用,在客户端看来只有接口,没有具体类实现。这样保证了代码的可扩展性和安全性。
在看了RPCClient如何使用,我们再来定义一个RPC服务器的接口,看看服务器都提供什么操作:
public interface Server { public void stop(); public void start(); public void register(Class interfaceDefiner,Class impl); public void call(Invocation invo); public boolean isRunning(); public int getPort(); }
服务器提供了start和stop方法。使用register注册一个接口和对应的实现类。call方法用于执行Invocation指定的接口的方法名。isRunning返回了服务器的状态,getPort()则返回了服务器使用的端口。
来看看Invocation的定义:
public class Invocation implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private Class interfaces; private Method method; private Object[] params; private Object result; /** * @return the result */ public Object getResult() { return result; } /** * @param result the result to set */ public void setResult(Object result) { this.result = result; } /** * @return the interfaces */ public Class getInterfaces() { return interfaces; } /** * @param interfaces the interfaces to set */ public void setInterfaces(Class interfaces) { this.interfaces = interfaces; } /** * @return the method */ public Method getMethod() { return method; } /** * @param method the method to set */ public void setMethod(Method method) { this.method = method; } /** * @return the params */ public Object[] getParams() { return params; } /** * @param params the params to set */ public void setParams(Object[] params) { this.params = params; } @Override public String toString() { return interfaces.getName()+"."+method.getMethodName()+"("+Arrays.toString(params)+")"; } }
具体服务器实现类中的call方法是这样使用Invocation的:
@Override public void call(Invocation invo) { Object obj = serviceEngine.get(invo.getInterfaces().getName()); //根据接口名,找到对应的处理类 if(obj!=null) { try { Method m = obj.getClass().getMethod(invo.getMethod().getMethodName(), invo.getMethod().getParams()); Object result = m.invoke(obj, invo.getParams()); invo.setResult(result); } catch (Throwable th) { th.printStackTrace(); } } else { throw new IllegalArgumentException("has no these class"); } }
下面来看服务器接收连接并处理连接请求的核心代码:
public class Listener extends Thread { private ServerSocket socket; private Server server; public Listener(Server server) { this.server = server; } @Override public void run() { System.out.println("启动服务器中,打开端口" + server.getPort()); try { socket = new ServerSocket(server.getPort()); } catch (IOException e1) { e1.printStackTrace(); return; } while (server.isRunning()) { try { Socket client = socket.accept(); ObjectInputStream ois = new ObjectInputStream(client.getInputStream()); Invocation invo = (Invocation) ois.readObject(); server.call(invo); ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream()); oos.writeObject(invo); oos.flush(); oos.close(); ois.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { if (socket != null && !socket.isClosed()) socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
RPC具体的Server类是这样来使用Listener的:
public static class RPCServer implements Server{ private int port = 20382; private Listener listener; private boolean isRuning = true; /** * @param isRuning the isRuning to set */ public void setRuning(boolean isRuning) { this.isRuning = isRuning; } /** * @return the port */ public int getPort() { return port; } /** * @param port the port to set */ public void setPort(int port) { this.port = port; } private Map<String ,Object> serviceEngine = new HashMap<String, Object>(); @Override public void call(Invocation invo) { System.out.println(invo.getClass().getName()); Object obj = serviceEngine.get(invo.getInterfaces().getName()); if(obj!=null) { try { Method m = obj.getClass().getMethod(invo.getMethod().getMethodName(), invo.getMethod().getParams()); Object result = m.invoke(obj, invo.getParams()); invo.setResult(result); } catch (Throwable th) { th.printStackTrace(); } } else { throw new IllegalArgumentException("has no these class"); } } @Override public void register(Class interfaceDefiner, Class impl) { try { this.serviceEngine.put(interfaceDefiner.getName(), impl.newInstance()); System.out.println(serviceEngine); } catch (Throwable e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void start() { System.out.println("启动服务器"); listener = new Listener(this); this.isRuning = true; listener.start(); } @Override public void stop() { this.setRuning(false); } @Override public boolean isRunning() { return isRuning; } }
服务器端代码搞定后,来看看客户端的代码,先看看我们刚开始使用RPC.getProxy方法:
public static <T> T getProxy(final Class<T> clazz,String host,int port) { final Client client = new Client(host,port); InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Invocation invo = new Invocation(); invo.setInterfaces(clazz); invo.setMethod(new org.jy.rpc.protocal.Method(method.getName(),method.getParameterTypes())); invo.setParams(args); client.invoke(invo); return invo.getResult(); } }; T t = (T) Proxy.newProxyInstance(RPC.class.getClassLoader(), new Class[] {clazz}, handler); return t; }
Client类的代码如下:
public class Client { private String host; private int port; private Socket socket; private ObjectOutputStream oos; private ObjectInputStream ois; public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public Client(String host, int port) { this.host = host; this.port = port; } public void init() throws UnknownHostException, IOException { socket = new Socket(host, port); oos = new ObjectOutputStream(socket.getOutputStream()); } public void invoke(Invocation invo) throws UnknownHostException, IOException, ClassNotFoundException { init(); System.out.println("写入数据"); oos.writeObject(invo); oos.flush(); ois = new ObjectInputStream(socket.getInputStream()); Invocation result = (Invocation) ois.readObject(); invo.setResult(result.getResult()); } }
至此,RPC的客户端和服务器端代码完成,启动服务器的代码如下:
public class Main { public static void main(String[] args) { Server server = new RPC.RPCServer(); server.register(Echo.class, RemoteEcho.class); server.start(); } }
现在先运行服务器端代码,再运行客户端代码,就可以成功运行。
详细的代码,参考附件的源代码。
在写这个RPC时,没有想太多。在数据串行化上,使用了java的标准io序列化机制,虽然不能跨平台,但是做DEMO还是不错的;另外在处理客户端请求上,使用了ServerSocket,而没有使用ServerSocketChannel这个java nio中的新特性;在动态生成接口的实现类上,使用了java.lang.reflet中的Proxy类。他可以动态创建接口的实现类。
- Rpc.rar (17.1 KB)
- 下载次数: 1335
评论
能否提供个跨平台的方案,比如android与J2SE双向通行
[*]
引用[color=cyan][/color]
[/list][/img][/flash]
我几年前也做过一个,考虑了跨平台。
http://code.google.com/p/rpcfx/
发表评论
-
这两天遇到代码中出现的两次多线程问题
2014-07-02 22:16 730这两天在做两个非常 ... -
打印一个数的加法组合
2011-10-19 16:12 2662下面的代码用于打印加法的组合。在打印时使用递归。思路来自 ... -
Java hashMap的 Hash函数
2011-09-16 14:35 3718在教科书提到的Hash函数就是求模了。Java的hash函数是 ... -
Java Arrays合并排序算法的实现
2011-09-16 13:28 1450下面再来看看Arrays里面的合并排序算法实现。先把完整的源代 ... -
Java Arrays 快速排序算法的实现
2011-09-16 12:48 3154我们知道Java在排序上分别使用了快速排序和合并排序。下 ... -
Java Arrays和Collections类的排序算法
2011-09-16 11:27 3459在Java的Arrays和Collections类里,分别提供 ... -
关于编码的若干最佳实践
2011-08-25 15:55 1287昨天XX面试时,一道 ... -
解决zookeeper linux下无法启动的问题
2011-07-05 10:54 41838在linux下安装zookeeper时 ... -
eclipse下编译hadoop源代码
2011-07-04 11:33 15074hadoop是一个分布式存储和分布式计算的框架。在日常使 ... -
[编程实现单链表逆转][java代码]
2011-06-14 18:13 4150代码如下,核心的代码在于: public stati ... -
StringBuffer vs StringBuilder、HashTable vs HashMap、Vector vs ArrayList
2011-06-09 18:35 1839在Java的面试题中很有可能问到的问题是Str ... -
[转] java.beans.PropertyEditor(属性编辑器)简单应用
2009-11-20 22:07 1571原文:http://www.blogjava.net/oran ...
相关推荐
自定义RPC(远程方法调用)的Java实现。
利用netty4.0定义的rpc通信框架
RPC—远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。此项目用的是java+netty+zookeeper构建的自定义rpc框架。
《netty实战》http协议、自定义协议、自定义RPC模块学习源码.zip
Java语言游戏项目实战资源包 内容概览: 这次分享为你带来了丰富的Java语言游戏项目实战资源,让你在实践中深入掌握Java语言,并开启游戏开发之旅。资源包中包括: 游戏项目代码:精心挑选了多个经典的小游戏项目...
基于Spring+netty+redis+自定义rpc(或者dubbo)+MyBatis + mysql(或者mongodb)实现。socket通信实现,登录系统,玩家线程模型,db系统,分布式id生成器,分布式锁,缓存系统,热更新机制,rpc系统,全服组队等等组织结构...
一个自定义的RPC框架示例
guide-rpc-framework ...通过这个简易的轮子,你可以学到RPC的替代原理和原理以及各种Java编码实践的运用。 你甚至可以把当做你的毕设/项目经验的选择,这是非常不错!对比其他求职者的项目经验都是各种系统,造轮子
Netty RPC基于Netty手动实现一个Java RPC框架快速使用约会依赖val nettyRpcVersion = " 0.0.1-SNAPSHOT "repositories { maven { setUrl( " https://maven.pkg.github.com/helloworlde/netty-rpc " ) }}dependencies...
包含RPC原理、NIO操作、netty简单的api、自定义RPC框架
通过这个简易的轮子,你可以学到 RPC 的底层原理和原理以及各种 Java 编码实践的运用。 你甚至可以把 当做你的毕设/项目经验的选择,这是非常不错!对比其他求职者的项目经验都是各种系统,造轮子肯定是更加能赢得...
rpc 基于netty实现的轻量级RPC框架 运用到如下技术和框架: JAVA动态代理spring自定义注释解netty框架zookeeper框架
该项目旨在提供轻松实现Java编程语言的JSON-RPC的功能。 jsonrpc4j使用库在json对象(以及与JSON-RPC相关的其他东西)之间来回转换java对象。 功能包括: 流服务器( InputStream \ OutputStream ) HTTP服务器...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
1、使用protostuff序列化(.proto文件编写恶心,与Protocol Buffer...后续计划使用该RPC完成基于JAVA的分布式文件服务、分布式KV数据库、部分低代码平台引擎等。过程中通过性能及功能测试对RPC本身进行不断完善及优化。
百度云盘分享 ... Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。 部分源代码摘录: ftpClient = new FtpClient(); //实例化FtpClient对象 String serverAddr=jtfServer.getText();...
Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。 部分源代码摘录: ftpClient = new FtpClient(); //实例化FtpClient对象 String serverAddr=jtfServer.getText(); //得到服务器地址 ...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...