前几天在阿里内推一面的时候,面试官问到了一个关于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中文件的操作

    文件的操作介绍 文件打开的方法 主要有两种: no with 格式:open(file, mode='r', buffering=-1, encoding=None, errors=None, new ...

  2. Java多线程volatile和synchronized总结

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

  3. spring AOP的两种配置方式

    连接点(JoinPoint) ,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的前.后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点.其他 ...

  4. jquery easyui datagrid数据自动换行 panel用法

    nowrap:false 初始化panel $('#txtLeftPercent').panel({ title: '剩余权重:' + percent, height: 10, width: 180, ...

  5. 配置文件错误导致jenkins无法启动 org.xmlpull.v1.XmlPullParserException: only 1.0 is supported as <?xml version not '1.1' (position: START_DOCUMENT seen <?xml version=\'1.1\'... @1:19)

    org.xmlpull.v1.XmlPullParserException: only 1.0 is supported as <?xml version not '1.1' (position ...

  6. aways on 配置部署(二)——配置域

    前一篇中我们基本了解了配置aways on的三个步骤,本篇就具体讲解如何配置域. DNS的配置 上篇可以看到三台服务器的ip地址,网关,DNS等配置,其中sqlDNS服务器的dns为自己的ip地址,s ...

  7. Oracle中rownum原理介绍

    rownum原理如下:1.执行查询操作2.将第一行的row num置为13.将得到的行的row num与条件相比较,如果不匹配,则抛弃行,如果匹配,则返回行4.oracle获取下一行,然后将rownu ...

  8. Unity中使用射线查询MeshCollider背面的方法

    之前遇到一个问题要从MeshCollider背面方向发出射线,直至检测到该射线与MeshCollider的相交点为止. 后来我用双面MeshCollider的方法解决了http://www.cnblo ...

  9. Jupyter Notebook 添加目录

    1.  安装 jupyter_contrib_nbextensions pip install jupyter_contrib_nbextensions 2. 配置 nbextension jupyt ...

  10. Swift基础之CoreData的使用

    以前使用过OC版本的CoreData应该很好理解Swift方式,所以这里简单的展示一下,增删改查的方法使用,同时给大家说一下创建步骤,方便大家的使用,转载请注明出处,谢谢~ 步骤一:创建一个Swift ...