前几天在阿里内推一面的时候,面试官问到了一个关于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. 分区工具PQ

    http://www.disktool.cn/jiaocheng/resize-partition.html

  2. node之querystring模块

    前言 querystring 模块提供了一些实用工具,用于解析与格式化 URL 查询字符串. 一.querystring.parse() 用于将一个查询字符串解析为JS 对象. const query ...

  3. JAVA局部内部类

    在刚刚学到的android开发中了解到Button的onClick是通过局部内部类的方式实现的,具体的原理我以后再去了解,只是遇到问题总是想知道为什么,不要告诉我这是规则,死记住就可以了. 问题是局部 ...

  4. c++ public,protected,private

    基类的私有成员被继承后不可见(优先级最高) 公有继承不改变基类成员属性 保护继承(私有继承)把基类成员变为保护成员(私有成员) public 公开的 protected 受保护的 private 私有 ...

  5. POJ 3050 Hopscotch DFS

    The cows play the child's game of hopscotch in a non-traditional way. Instead of a linear set of num ...

  6. Spring Boot+maven打war包

    存在一个坑: 官网文档 指出以下前3步做法,但是这样只可以打出可运行的jar包,要打出war包还要在文档后面的链接跳到另一个页面,才能找到第四步的做法,也就是最终能够打出war包,可能有些朋友有些粗心 ...

  7. 解读Batch Normalization

    原文转自:http://blog.csdn.net/shuzfan/article/details/50723877 本次所讲的内容为Batch Normalization,简称BN,来源于<B ...

  8. 学习笔记:Zookeeper 应用案例(上下线动态感知)

    1.Zookeeper 应用案例(上下线动态感知) 8.1 案例1--服务器上下线动态感知 8.1.1 需求描述 某分布式系统中,主节点可以有多台,可以动态上下线 任意一台客户端都能实时感知到主节点服 ...

  9. Gradle 1.12用户指南翻译——第五十三章. 签名插件

    其他章节的翻译请参见:http://blog.csdn.net/column/details/gradle-translation.html翻译项目请关注Github上的地址:https://gith ...

  10. 一小时入门PHP

    [版权申明:本文系作者原创,转载请注明出处] 文章出处:[http://blog.csdn.net/sdksdk0/article/details/52332296](http://blog.csdn ...