Java RMI原理与使用

Java RMI 指的是远程方法调用 (Remote Method Invocation)。它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。

Java RMI概念

在Java中,只要一个类继承了java.rmi.Remote接口,即可成为存在于服务器端的远程对象,供客户端访问并提供一定的服务。JavaDoc描述:Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在“远程接口”(扩展 java.rmi.Remote 的接口)中指定的这些方法才可远程使用。

编写一个RMI的步骤

1. 定义一个远程接口,此接口需要继承Remote
2. 开发远程接口的实现类
3. 创建一个server并把远程对象注册到端口
4. 创建一个client查找远程对象,调用远程方法

一个Hello Word的远程调用实例

定义一个远程接口

编写RMI应用的第一步就是先定义远程接口。远程接口必须继承java.rmi.Remote接口,并且声明自己的远程方法。为了处理远程方法发生的各种异常,每一个远程方法必须抛出一个java.rmi.RemoteException异常。

public interface RemoteHelloWord extends Remote {
  String sayHello() throws RemoteException;
}

这个远程接口只定义了一个远程方法 sayHello(),远程方法在调用的时候有可能失败比如发生网络问题或者server挂掉,此时远程方法会抛出RemoteException异常。

开发接口的实现类

开发接口的实现类,即具体的远程对象,在远程对象中实现远程接口中定义的方法。

public class RemoteHelloWordImpl  implements RemoteHelloWord{
    @Override
    public String sayHello() throws RemoteException {
        return "Hello Word!";
    }
}

创建一个Server并把对象注册到端口

在server端只需要做两件事:

  1. 创建并导出远程对象
  2. Java RMI registry 注册远程对象

下面是一个server端的程序:

public class RMIServer {
public static void main(String[] args) {
    try {
        RemoteHelloWord hello=new RemoteHelloWordImpl();
        RemoteHelloWord stub=(RemoteHelloWord)UnicastRemoteObject.exportObject(hello, 9999);
        LocateRegistry.createRegistry(1099);
        Registry registry=LocateRegistry.getRegistry();
        registry.bind("helloword", stub);
        System.out.println("绑定成功!");
    } catch (RemoteException e) {
        e.printStackTrace();
    } catch (AlreadyBoundException e) {
        e.printStackTrace();
    }
}
}

关于创建和导出远程对象

RemoteHelloWord stub=(RemoteHelloWord)UnicastRemoteObject.exportObject(new RemoteHelloWordImpl(), 0);

Server端的main方法在创建一个远程对象来提供服务时,此远程对象必须被导出才能被远程调用者调用。静态方法UnicastRemoteObject.exportObject()负责导出我们定义好的远程对象,并用任意一个tcp端口来接收远程方法调用,同时,它还会返回一个存根,这个存根将会发送给client端进行调用。当exportObject()方法被执行后,运行时会在一个新的Server Socket或共享Server Socket上进行监听,来接收对远程对象的远程调用。返回的存根对象和远程对象继承的是同一套remote接口(为了实现代理模式),并且还它还包含了供client端口访问的主机IP和端口信息。

用Java RMI registry注册远程对象

Registry registry=LocateRegistry.getRegistry();
registry.bind( "helloword", stub);

为了使client能够调用远程对象的方法,client必须持有远程对象的存根,为此,Java RMI 提供了registry API 可以允许应用程序把一个名称和远程对象的存根绑定在一起,这样client就可以通过这个绑定的名称很方便的查找到需要调用的远程对象了,在这里可以把registry看做是一个名称服务,实现了工厂模式(提供具体的远程对象)和代理模式(代理server端具体处理client端的请求)。

一旦远程对象在server端导出并注册,client就可以通过绑定的名称获得远程对象的引用,然后调用远程方法。

静态方法Registry registry=LocateRegistry.getRegistry()会返回一个实现了java.rmi.registry.Registry接口的存根,并且在服务器本机的端口(默认是1099)上进行注册,返回的registry存根通过调用bind()方法在registry中把一个字符串名称和远程对象存根绑定在一起。

创建一个client查找远程对象,调用远程方法

public class RMIClient {
  public static void main(String[] args) {
         try {
              Registry registry = LocateRegistry.getRegistry("localhost");
              RemoteHelloWord hello = (RemoteHelloWord) registry.lookup( "helloword");
              String ret = hello.sayHello();
              System. out.println( ret);
        } catch (RemoteException e) {
               e.printStackTrace();
        } catch (NotBoundException e) {
               e.printStackTrace();
        }
  }

}

客户端首先通过LocateRegistry.getRegistry("localhost")方法获得registry的存根,然后再执行registry存根的lookup()方法从服务器registry中获得远程对象的存根,最后客户端在远程对象存根上执行sayHello()方法。整个过程可以描述为:

  • 客户端通过远程对象存根中的IP和端口打开一个服务器连接,并且序列化请求数据
  • 服务器端接收请求并且转发请求到远程对象调用服务方法,并且序列化运行结果发送给客户端
  • 客户端接收数据反序列化,把最终结果返回给调用者

结果测试

启动server,然后在启动client,控制台打印:

Hello Word!

Java RMI中用到的设计模式

Java RMI中用到了经典的工厂模式和代理模式,先介绍下Java RMI应用的一些角色:

  1. server:生产各种远程对象
  2. client:通过命名服务器rmiregistry获取远程对象的存根
  3. rmiregistry:具体处理client与server的交流

下面这幅图演示了整个步骤,下图中先做如下假设:

  • 有两个远程服务接口可供client调用,Factory和Product接口
  • FactoryImpl类实现了Factory接口,ProductImpl类实现了Product接口

1. FactoryImpl被注册到了rmiregistry中
2. client端请求一个Factory的引用
3. rmiregistry返回client端一个FactoryImpl的引用
4. client端调用FactoryImpl的远程方法请求一个ProductImpl的远程引用
5. FactoryImpl返回给client端一个ProductImpl引用
6. client通过ProductImpl引用调用远程方法
时间: 2024-10-01 15:05:09

Java RMI原理与使用的相关文章

java RMI原理详解

[本文转载自java RMI原理详解] 定义 RMI(Remote Method Invocation)为远程方法调用,是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法. 这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中. Java RMI:Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口.它使客户机上运行的程序

Java RMI(远程方法调用) 实例与分析 (转)

目的: 通过本文,可以加深对Java RMI的理解,知道它的工作原理,怎么使用等. 也为了加深我自己的理解,故整理成文.不足之处,还望指出. 概念解释: RMI(RemoteMethodInvocation):远程方法调用,顾名思义,通过远程的方式调用非本地对象的方法并返回结果.使用远程调用通常解决本地计算瓶颈问题,例如分布式记算,最近很火的阿尔法狗人机大战,据说运算使用上千个CPU. JRMP(java remote method protocol):java远程方法协议,这是完成java到j

Java——RMI

      之前分布式系统调用用的是比较老的EJB,当时还是作为服务调用方,去调用别的系统的服务.最近发现新公司里面,用的是RMI,查了下发现EJB的底层实现就是RMI,也算是熟悉了...  一,使用JDK 中的RMI实现服务发布和引用 服务端接口: /** * Created by LiuHuiChao on 2016/11/18. */ public interface UserInfoService extends Remote{ /** * 定义远程接口,必须继承Remote接口, *

Java RMI 简单示例

示例 RMI是Java平台实现远程调用的规范,下面是一个小例子,本机测试通过 一共有三个java类,远程接口,服务端程序,客户端程序 远程接口: import java.rmi.*; public interface HelloIn extends java.rmi.Remote{ String sayHello() throws RemoteException;} 服务端程序: import java.rmi.*;import java.net.*;import java.rmi.regist

十分钟学会Java RMI

RMI是Java平台实现远程调用的规范,下面是一个小例子,本机测试通过 一共有三个java类,远程接口,服务端程序,客户端程序 远程接口: import java.rmi.*; public interface HelloIn extends java.rmi.Remote{ String sayHello() throws RemoteException; } 服务端程序: /** * author by http://www.bt285.cn http://www.5a520.cn */ i

java类的问题-java递归原理求高人解惑

问题描述 java递归原理求高人解惑 int i=1;int Test(int n){ System.out.println(""*****************""+(i++)); int result =0; if(n==1) return 1; result = Test(n-1)*n; System.out.println(result+"" ""+n); return result;}我进行调试,比如n=8,只打印

gc-通过Java RMI的定时GC触发,JVM垃圾回收就无法自动触发FULL GC了吗?

问题描述 通过Java RMI的定时GC触发,JVM垃圾回收就无法自动触发FULL GC了吗? Java RMI的定时GC触发机制,可通过:-XX:+DisableExplicitGC来禁止或通过 -Dsun.rmi.dgc.server.gcInterval=3600000来控制触发的时间. 那么问题来了堆栈内存满了,是否就不会自动触发FULL GC了. 目前系统几次宕机,看内存监控均为堆栈满了,但是没能触发FULL GC. 看应用服务启动配置中有Dsun.rmi.dgc.server.gcI

Java类加载原理解析

1       基本信息 摘要: 每个java开发人员对java.lang.ClassNotFoundExcetpion这个异常肯定都不陌生,这背后就涉及到了java技术体系中的类加载.Java的类加载机制是java技术体系中比较核心的部分,虽然和大部分开发人员直接打交道不多,但是对其背后的机理有一定理解有助于排查程序中出现的类加载失败等技术问题,对理解java虚拟机的连接模型和java语言的动态性都有很大帮助. 由于关于java类加载的内容较多,所以打算分三篇文章简述一下: 第一篇:java类

java rmi连接远程主机问题

问题描述 java rmi连接远程主机问题 问题是这样的,通过rmi来实现分布式通信,用的是20112端口,在本地实现的时候是没问题的,但是部署到主机(亚马逊云机,供外访问ip:54.**.72.52,内部IP是10.0.3.9,有防火墙,但是已经打开20112和20110端口),就不能访问了,错误 java.rmi.ConnectionException:Connetcion refused to host:10.0.3.9;nested exception: java.net.conneti