RMI(Remote Method Invocation)是Java中的远程过程调用(Remote Procedure Call,RPC)实现,是一种分布式Java应用的实现方式。它的目的在于对开发人员屏蔽横跨不同JVM和网络连接等细节,使得分布在不同JVM上的对象像是存在于一个统一的JVM中一样,可以很方便的互相通讯。之所以在介绍对象序列化之后来介绍RMI,主要是因为对象序列化机制使得RMI非常简单。调用一个远程服务器上的方法并不是一件困难的事情。开发人员可以基于Apache MINA或是Netty这样的框架来写自己的网络服务器,亦或是可以采用REST架构风格来编写HTTP服务。但这些解决方案中,不可回避的一个部分就是数据的编排和解排(marshal/unmarshal)。需要在Java对象和传输格式之间进行互相转换,而且这一部分逻辑是开发人员无法回避的。RMI的优势在于依靠Java序列化机制,对开发人员屏蔽了数据编排和解排的细节,要做的事情非常少。JDK 5之后,RMI通过动态代理机制去掉了早期版本中需要通过工具进行代码生成的繁琐方式,使用起来更加简单。
RMI采用的是典型的客户端-服务器端架构。首先需要定义的是服务器端的远程接口,这一步是设计好服务器端需要提供什么样的服务。对远程接口的要求很简单,只需要继承自RMI中的Remote接口即可。Remote和Serializable一样,也是标记接口。远程接口中的方法需要抛出RemoteException。定义好远程接口之后,实现该接口即可。如下面的Calculator是一个简单的远程接口。
public interface Calculator extends Remote { String calculate(String expr) throws RemoteException;}
实现了远程接口的类的实例称为远程对象。创建出远程对象之后,需要把它注册到一个注册表之中。这是为了客户端能够找到该远程对象并调用。
public class CalculatorServer implements Calculator { public String calculate(String expr) throws RemoteException { return expr; } public void start() throws RemoteException, AlreadyBoundException { Calculator stub = (Calculator) UnicastRemoteObject.exportObject(this, 0); Registry registry = LocateRegistry.getRegistry(); registry.rebind("Calculator", stub); }}
CalculatorServer是远程对象的Java类。在它的start方法中通过UnicastRemoteObject的exportObject把当前对象暴露出来,使得它可以接收来自客户端的调用请求。再通过Registry的rebind方法进行注册,使得客户端可以查找到。
客户端的实现就是首先从注册表中查找到远程接口的实现对象,再调用相应的方法即可。实际的调用虽然是在服务器端完成的,但是在客户端看来,这个接口中的方法就好像是在当前JVM中一样。这就是RMI的强大之处。
public class CalculatorClient { public void calculate(String expr) { try { Registry registry = LocateRegistry.getRegistry("localhost"); Calculator calculator = (Calculator) registry.lookup("Calculator"); String result = calculator.calculate(expr); System.out.println(result); } catch (Exception e) { e.printStackTrace(); } }}
在运行的时候,需要首先通过rmiregistry命令来启动RMI中用到的注册表服务器。
为了通过Java的序列化机制来进行传输,远程接口中的方法的参数和返回值,要么是Java的基本类型,要么是远程对象,要么是实现了 Serializable接口的Java类。当客户端通过RMI注册表找到一个远程接口的时候,所得到的其实是远程接口的一个动态代理对象。当客户端调用其中的方法的时候,方法的参数对象会在序列化之后,传输到服务器端。服务器端接收到之后,进行反序列化得到参数对象。并使用这些参数对象,在服务器端调用实际的方法。调用的返回值Java对象经过序列化之后,再发送回客户端。客户端再经过反序列化之后得到Java对象,返回给调用者。这中间的序列化过程对于使用者来说是透明的,由动态代理对象自动完成。除了序列化之外,RMI还使用了动态类加载技术。当需要进行反序列化的时候,如果该对象的类定义在当前JVM中没有找到,RMI会尝试从远端下载所需的类文件定义。可以在RMI程序启动的时候,通过JVM参数java.rmi.server.codebase来指定动态下载Java类文件的URL。
相关推荐
本文档主要讲述的是Java 远程方法调用RMI参数详解;根据RMI参数意义,可以归结为以下几点,我们可以根据这几点通过优化GC, 网络等待,流传输协议(http/rmi special socket)等方面来优化RMI。
java进程间通讯机制代码----RMI、共享内存、Socket、管道,等方式,每种方法我都讲了原理和例子程序,很有参考意义。在网上很难找到的。
第10章-使用Java-2进行RMI编程教学课件PPT文档.pptx
Babel-Java-RMI Java RMI 服务器 + 带有 JSON 转换器的客户端
java教学课件:10Java--RMI.ppt
Actual Java RMI implementation
java-RMI技术讲解
java rmi java rmijava rmi javajava rmi java rmi rmi
通过java rmi 与java applet技术,实现两台主机的通信功能,有详细的源码。
echo 'PROJECT_PATH=/Users/arthur.branco/Documents/code/puc/repos/election-java-rmi-arthurgbranco"' >> ./config.sh 执行脚本 chmod +x compile.sh ./compile.sh 意大利面食的制作和面食的执行 cd ./bin ...
java rmi远程调用服务器搭建,rmi具体实现步骤说明,
该系统是使用JAVA RMI技术开发的,具有Socket编程和用于大学项目的多线程。
本项目使用socket直接发送数据包来攻击rmi,通过反序列化攻击rmi,双击直接运行,对1099端口的rmi服务直接进行漏洞检测。
由于Java具有跨平台、代码可移植性、安全高效等广泛而强大的功能,因而在开发网络分布式应用的时候,可以用它自身的机制实现分布式计算,一种基于Java的远程方法调用(RMI)为我们开发企业分布式应用提供了行之有效的...
java-simple-RMI RMI:远程方法调用 使用Java反射的简单RMI的服务器和客户端实现
durham大学的RMI(远程方法调用)教程,主要讲解了有关JAVA环境下RMI的使用方法。
在这次的项目中,对于客户端与服务器之间的通信,想了许多办法,由于做的是富客户端应用,最终将技术选定在了RMI和Java-sockets两种之间,其中RMI的灵活性不高,客户端和服务器端都必须是java编写,但使用比较方便,...
Java使用序列化的方式,可以实现远端的方法调用;java_rmi命令执行利用工具
Java-RMI Java 中的 RMI 实现,作为卡内基梅隆大学 15-440 分布式系统课程的一部分创建