RMI理论知识

1、什么是RMI?

  Java 远程方法调用,即Java RMI(Java Remote Method Invocation)。顾名思义,可以使客户机上运行的程序能够调用远程服务器上的对象(方法)。

  在Java世界里,有一种技术可以实现“跨虚拟机”的调用,它就是RMI(Remote Method Invocation,远程方法调用)。例如,服务A 在 JVM1 中运行,服务B在JVM2 中运行,服务A与服务B可相互进行远程调用,就像调用本地方法一样,这就是 RMI。

  通过RMI技术,本地虚拟机JVM可以调用存在于另外一个JVM中的对象方法,就好像该虚拟机调用存在于本地JVM的某个对象方法一样。而另外一个JVM可以与本地JVM在同一台物理机,也可以属于不同的物理机。

  RMI是Java的一组拥护开发分布式应用程序的API。RMI使用Java语言接口定义了远程对象,它集合了Java序列化和Java远程方法协议(Java Remote Method Protocol)。

2、原理

  在RMI中,客户端的代理对象被称为存根(Stub),存根位于客户端机器上,它知道如何通过网络与服务器联系。存根会将远程方法所需的参数打包成一组字节。对参数编码的过程被称为参数编组(parameter marshalling),参数编组的目的是将参数转换成适合在虚拟机之间进行传递的形式。在RMI协议中,对象是使用序列化机制进行编码的。

总的来说,客户端的存根方法构造了一个信息块,它由以下几部分组成:

  1)被使用的远程对象的标识符;

  2)被调用的方法的描述;

  3)编组后的参数。

然后,存根将此信息发送给服务器。在服务器的一端,接收器对象执行以下动作:

  1) 定位要调用的远程对象;

  2) 调用所需的方法,并传递客户端提供的参数;

  3) 捕获返回值或调用产生的异常;

  4) 将返回值编组,打包送回给客户端存根。

客户端存根对来自服务器端的返回值或异常进行反编组,其结果就成为了调用存根返回值。

简而言之,其实现过程:

 

RMI远程调用步骤:

  1)客户调用客户端辅助对象stub上的方法;

  2)客户端辅助对象stub打包调用信息(变量,方法名),通过网络发送给服务端辅助对象skeleton;

  3)服务端辅助对象skeleton将客户端辅助对象发送来的信息解包,找出真正被调用的方法以及该方法所在对象;

  4)调用真正服务对象上的真正方法,并将结果返回给服务端辅助对象skeleton;

  5)服务端辅助对象将结果打包,发送给客户端辅助对象stub;

  6)客户端辅助对象将返回值解包,返回给调用者;

  7)客户获得返回值。

3、几个重要概念说明

  RMI 注册表(可参考 LocateRegistry 类)

  1)为了使得客户端能够查找到服务端对外提供的远程对象,RMI需要维护一个RMI注册表,该注册表维护了对于客户端而言的远程对象位置,对外提供了服务,服务端需要将要外提供服务的对象的代理绑定到RMI注册表中;

  2)RMI注册表可以跟服务端不在一台主机上;

  3)RMI注册表的启动有两种方式:一种是通过命令行rmiregistry$port在命令行启动;另外一种是通过LocateRegistry类的createRegistry(int port)方法启动。

  客户端查找远程对象,服务端注册远程对象的多样性

注册服务共有三种方式:

  1)LocateRegistry类的对象的rebind()和lookup()来实现绑定注册和查找远程对象的;

  2)利用命名服务java.rmi.Naming类的rebind()和lookup()来实现绑定注册和查找远程对象的;

  3)利用JNDI(Java Naming and Directory Interface,Java命名和目录接口) java.naming.InitialContext类来rebind()和lookup()来实现绑定注册和查找远程对象的。

实际上java.rmi.Naming类的rebind()和lookup()方法只是在LocateRegistry 类的简单封装,该类的源码

// Naming 类的部分源码 (为了节省篇幅,去除了抛出异常部分)
public static void bind(String name, Remote obj) throws ...
{
    ParsedNamingURL parsed = parseURL(name);
    Registry registry = getRegistry(parsed);
    if (obj == null)
        throw new NullPointerException("cannot bind to null");
    registry.bind(parsed.name, obj);
}

  通过LocateRegistry.getRegistry方法来确定Registry的位置,然后通过registry.bind方法绑定name和obj,上述两步骤完成,但是可以通过Naming.bind方法一步直接完成。

4、RMI涉及到安全机制方面的问题

  在完成本机运行后实际上对于RMI的认识还是非常肤浅的,而网络上对于在服务端和客户端程序运行的两台不同物理主机的RMI示例内容很少,而Oracel提供的官方文档 JDK 1.5的RMI教程 最新的教程 也没有一个可以完美地在两台机器上跑起来。

  对于在本机运行客户端、服务端以及RMI注册表服务不涉及到安全性问题,当把客户端的代码扔到另一台物理机,首先遇到的问题是no security manager: RMI class loader disable;这时,首先需要了解Java的安全机制中涉及到的SecurityManager类和安全策略文件 policy 的写法和各个字段的含义。

 SecurityManager的加入方式:

  (1)在编码中加入:System.setSecurityManager(new SecurityManager());

  (2)在命令行中加入:java -Djava.security.manager

 既然加入了安全管理器,那么也需要对应的安全策略文件,如果主动指定策略文件,将使用默认策略文件:

  1)在编码中加入:System.setProperty("java.security.policy","策略文件路径")

  2)在命令行加入:java -Djava.security.policy=MyApp.policy

关于 policy 文件的形式说明:

grant codesource{
      permission1;
      permission2;
       ...
 };

codesource的一般形式是codeBase "url地址",基本含义是赋予codesource中的代码permission1, permission2 ...等权限,如果省略的 codesource 如下面这样,说明 permission 权限被赋予给了所有代码:

grant{
   permission1;
}

5、远程类文件的加载问题

  在两台不同的物理主机部署RMI程序时碰到的另外常见问题是 ClassNotFoundException,这个问题产生的原因对于客户端来说有3个:

  1)本机运行的客户端的客户端代码-classpath的指定问题;

  2)本机运行的客户端代码中需要跟服务端代码同步的部分不一致,RMI运行过程中会检查一致性。比如Remote接口的代码与服务端不一致,在部署过程中服务端的远程接口是位于包中,而在客户端的远程接口代码为了图方便自己写的,结果没有在包中。最后在解决了 securityManager 问题后一直卡在这里,最后发现了包名出现在异常中,索性将服务端代码都放到默认包中了,问题立马解决了。

  3)RMI运行时客户端有时需要从远程获取.class文件(由于本地 classpath 中没有,而远程方法中的参数或则返回值包含了可序列化的对象,此时RMI可以通过网络从指定路径获取),使用 -Djava.rmi.server.codebase= http://webvector/export/(示例地址)来指定

  实际上客户端、服务端、RMI注册表、公共类文件可以分别位于不同主机上,此时涉及到的 ClassNotFoundException 则会更加多,这里不在赘述,出错的原因都是类似的,客户端,服务端,RMI注册程序运行时都可以指定 -Djava.rmi.server.codebase=http://webvector/export/(示例地址)参数。

 

  参考:https://blog.csdn.net/yinwenjie/article/details/49120813

6.应用

  RMI适用于两个系统都主要使用JAVA语言进行构造,不需要考虑跨语言支持的情况。并且对两个JAVA系统的通讯速度有要求的情况。

  RMI 是一个良好的、特殊的RPC实现:使用JRMP协议承载数据描述,可以使用BIO和NIO两种IO通信模型。RMI框架是可以在大规模集群系统中使用的

  Java RMI不是什么新技术(在Java1.1的时代都有了),但却是是非常重要的底层技术,大名鼎鼎的EJB都是建立在rmi基础之上的,现在还有一些开源的远程调用组件,其底层技术也是rmi。

参考文献:

 

  http://www.importnew.com/20344.html

 

  https://blog.csdn.net/cuixianlong/article/details/57627187

 

  https://www.cnblogs.com/ygj0930/p/6542811.html

 

  https://www.cnblogs.com/zawier/p/7043855.html

 

  https://segmentfault.com/a/1190000004494341

 

  http://www.blogjava.net/zhenyu33154/articles/320245.html

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值