前几天在阿里内推一面的时候,面试官问到了一个关于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中模块之xml的讲解

    xml模块的功能介绍 这里主要讲解xml模块下的etree.ElementTree类. 1. 创建 具体代码如下 import xml.etree.ElementTree as XM namelist ...

  2. 从 vCenter Server 使用的数据库中清除旧数据 (2075138)(转)

    Document Id 2075138 Symptoms 免责声明: 本文为 Purging old data from the database used by VMware vCenter Ser ...

  3. c# error

    部署iis c# 连sqlserver 用IIS发布之后,网页出错.提示为:异常详细信息: System.Data.SqlClient.SqlException: 用户 'NT AUTHORITY\I ...

  4. 《Python黑帽子》_1设置Python环境安装wingIDE

    1首先你得有个Kali 检测python版本 安装pip 2安装wingIDE 网站 http://www.wingware.com 获取WingIDE 3解压wingide并且解决依赖关系 下载后在 ...

  5. Eleven

    A. Eleven time limit per test : 1 second memory limit per test:  256 megabytes input:  standard inpu ...

  6. Go 语言函数

    函数是基本的代码块,用于执行一个任务. Go 语言最少有个 main() 函数. 你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务. 函数声明告诉了编译器函数的名称,返回类型,和参数. ...

  7. Bootstrap3 表单-输出内联表单

    为 <form> 元素添加 .form-inline 类可使其内容左对齐并且表现为 inline-block 级别的控件.只适用于视口(viewport)至少在 768px 宽度时(视口宽 ...

  8. Android app内存管理的16点建议

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiopshared memory(共享内存) Android通过下面几个方式在不同的Process中来共享RAM: 每一个app的proc ...

  9. 微信开发之使用java获取签名signature(贴源码,附工程)

    一.前言 微信接口调用验证最终需要用到的三个参数noncestr.timestamp.signature: 接下来将会给出获取这三个参数的详细代码 本文的环境eclipse + maven 本文使用到 ...

  10. memcached实战系列(七)理解Memcached的数据过期方式、新建过程、查找过程

    1.1.1. 新建Item分配内存过程 1:快速定位slab classid,先计算Item长度 key键长+flag+suffix(16字节)+value值长+结构大小(32字节),如90byte ...