前几天在阿里内推一面的时候,面试官问到了一个关于java中RMI(Remote Method Invocation)的问题,当时感觉自己回答的还比较好,他比较满意,但那是因为他问的比较浅,所以自己看了一些关于java方面的书籍及网上相关资料,根据自己的理解,谈谈java中的RMI。

java中的RMI包括两种情况,一种是采用反射机制,另一种是采用实现Remote接口的方式,下面一一介绍。

一采用反射机制:

关于此种方式不过多讲述,请参看孙卫琴老师的java网络编程P242中10.2小节在远程方法调用中运用反射机制

二实现Remote接口:

先了解一些最基本的概念:

1远程对象:驻留在远程服务器上的对象是客户端要请求的对象,称作远程对象,即客户端请求远程对象调用相应的方法完成一定的业务逻辑,然后远程对象调用该方法将结果返回给客户端。

2代理与存根(Stub)

RMI不希望客户端直接与远程对象打交道,而是代之以让客户端与远程对象的代理打交道。代理的特点是:它与远程对象实现了相同的接口,也就是说它与远程对象向客户端公开了相同的方法,当客户端请求代理调用这个方法时,如果代理确认远程对象能够能够调用相同的方法,就会把实际的方法调用委派给远程对象。这种情况非常类似国家领导人与驻外国大使的关系,如果中国的某个官员要联系美国总统,需要先和驻中国的美国大使联系,然后通过他和美国总统联系,这个大使就相当于总统的远程代理对象。

RMI会帮助生成一个存根(Stub),一种特殊的字节码,让这个存根产生的对象作为远程对象的代理,代理需要驻留在客户端,即客户端需要把RMI生成的存根(Stub)复制或下载到客户端。

3Remote接口

RMI为了标识一个对象是远程对象,即为了标识该对象能够被客户端请求,需要远程对象必须实现java.rmi包中的Remote接口,也就是说只有实现了该接口的类的实例才被RMI认为是一个远程对象。Remote接口中没任何方法,仅仅起一个标识作用,因此必须扩展该接口,用来规定远程对象哪些方法是客户可以请求的。

原理示意图如下:

具体实现步骤如下:

1扩展Remote接口:定义一个接口是java.rmi包中Remote的子接口,在该接口中定义一个方法用来规定远程对象哪些方法是客户可以请求的。代码如下

package rmi;

import java.rmi.Remote;

public interface  RemoteSubject extends Remote {

	public void setHeigh(double height);
public void setWidth(double width);
public double getArea(); }

2创建远程对象:远程对象需要实现上述扩展的Remote接口,另外,RMI为了让一个对象成为远程对象还需要做一些初始化工作,该工作java中的UnicastRemoteObject已经帮我们做好了,我们只需要继承它既可。即远程对象需要实现上述扩展的Remote接口同时继承UnicastRemoteObject类(位于java.rmi.server包中)

package rmi;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject; public class RemoteConcreteSubject extends UnicastRemoteObject implements RemoteSubject { private double width,height;
protected RemoteConcreteSubject() throws RemoteException {
super();
// TODO Auto-generated constructor stub
} @Override
public void setHeigh(double height) {
// TODO Auto-generated method stub
this.height=height;
} @Override
public void setWidth(double width) {
// TODO Auto-generated method stub
this.width=width;
} public double getArea()
{ return width*height;
}
}

3产生存根(即代理):我们使用rmic命令 远程对象类名.java文件,则会自动产生一个存根字节码文件,注意存根是在服务器端产生的,通常提供一个web服务让客户端下载该存根

4启动注册:rmiregistry:在启动远程服务器创建远程对象之前,RMI要求远程服务器必须首先启动注册rmiregistry,启动之后服务器才可以创建远程对象,然后将该远程对象注册到rmiregistry所管理的注册表中。在远程终端执行rmiregistry命令即可启动注册。

5启动远程对象服务:即服务器端运行的业务逻辑代码,远程服务通过使用java.rmi包中的Naming类调用rebind(String name,Remote obj)方法绑定一个远程对象到rmiregistry:所管理的注册表中,该方法的name参数是URL格式,obj是远程对象,将来客户端的代理将通过name找到远程对象obj.。

package rmi;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException; public class BindRemoteObjectServer { public static void main(String[] args) {
// TODO Auto-generated method stub try {
RemoteConcreteSubject remoteObject=new RemoteConcreteSubject();
Naming.rebind("rmi://127.0.0.1/rect",remoteObject);
System.out.println("ready for client....");
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } }

6运行客户端程序:远程服务器端启动远程服务之后,客户端就可以运行相关程序,访问和使用远程对象。客户端使用java.rmi包中的Naming类的lookup(String name)返回一个远程对象的代理,即使用存根产生一个和远程对象具备相同接口的对象,lookup(String nane)方法中的name参数的值必须是远程对象注册的name,如:“rmi://127.0.0.1/rect”

客户端可以像使用远程对象一样来使用lookup(String nane)方法返回的远程对象的代理,这就类似上述反射机制中通过反射得到服务器端的类之后就可以调用其中个的一些方法。

package rmi;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException; public class ClientApplication { public static void main(String[] args) {
// TODO Auto-generated method stub try {
Remote remoteObject=Naming.lookup("rmi://127.0.0.1/rect");
RemoteSubject remoteSubject=(RemoteSubject)remoteObject;
remoteSubject .setWidth(127);
remoteSubject.setHeigh(520);
double area=remoteSubject.getArea();
System.out.println(area);
} catch (MalformedURLException | RemoteException | NotBoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } }





javaRMI详解的更多相关文章

  1. jdk目录详解及其使用方法

    jdk目录详解 jdk目录详解 JDK(Java Development Kit,Java开发包,Java开发工具)是一个写Java的applet和应用程序的程序开发环境.它由一个处于操作系统层之上的 ...

  2. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  3. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  4. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  5. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  6. Android Notification 详解(一)——基本操作

    Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...

  7. Android Notification 详解——基本操作

    Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...

  8. Git初探--笔记整理和Git命令详解

    几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...

  9. Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)

    Android XML shape 标签使用详解   一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...

随机推荐

  1. Python-闭包详解

    在函数编程中经常用到闭包.闭包是什么,它是怎么产生的及用来解决什么问题呢.给出字面的定义先:闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)(想想Erlang的外层函数传入一个 ...

  2. java的迭代器详解

    迭代器的引出 在jdk1.5版本之前是没有 foreach的,然而1.5版本就加上了foreach,而引入的新的foreach功能并不是在jvm上进行改进的因为代价太高,甲骨文工程师想到了一个比较好的 ...

  3. Java多线程volatile和synchronized总结

    volatile是轻量级的synchronized,在多处理器(多线程)开发中保证了共享变量的"可见性".可见性表示当一个线程修改了一个共享变量时,另外一个线程能读到这个修改的值. ...

  4. 软件测试assert

    之前实习做过一段时间测试,现做个总结: 实习测试的是一款CM系统(case 系统),来记录IT部门处理的维修,服务,反馈,预定服务等case:b/s架构,人少小项目,实习时间短,去了已经快完工,主要测 ...

  5. event工具集

    eventTool = { // 页面加载完成后 readyEvent : function(fn) { if (fn==null) { fn=document; } var oldonload = ...

  6. web领域的实时推送技术-WebSocket

    WebSocket protocol 是HTML5一种新的协议.它实现了浏览器与服务器全双工通信(full-duplex),即是所谓的及时推送技术. 在此之前,很多网站为了实现及时推送技术通常采用的是 ...

  7. 项目中BigDecimal与Double使用场景

    金额要用BigDecimal 金额计算不能用doube!!!! 金额计算必须用BigDecimal,下面对比一下用double 跟BigDecimal的区别.先看一个小例子: 请看题: 示例1 问, ...

  8. WPF TextBlock 判断 isTextTrimmed 文本是否超出

    WPF TextBlock 设置TextTrimming情况下 判断 isTextTrimmed(Text 文本是否超出 是否出现了省略号) private bool HasTextTrimmed(T ...

  9. NPOI给单元格加范围边框

    HSSFWorkbook workbook2 = new HSSFWorkbook();        //XSSFWorkbook workbook2 = new XSSFWorkbook();// ...

  10. 02 基础设施/Gitlab - DevOps之路

    基础设施/Gitlab - DevOps之路 文章Github地址,欢迎start:https://github.com/li-keli/DevOps-WiKi 源代码管理器选用Gitlab,新版(2 ...