【Java基础】- RMI原理和使用详解

简介: 【Java基础】- RMI原理和使用详解

一、什么RMI

RMI:远程方法调佣(Remort Method Invocation),它支持存储于不同地址空间的程序级对象之间彼此通信,实现远程对象之间的无缝远程调用。

JAVA RMI:用于不同虚拟机之间的通信,这些虚拟机可以在不同的主机上,也可以在同一个主机上;一个虚拟机中的对象调用另一个虚拟机上中的对象的方法,只不过是允许被远程调用的对象要通过一些标志加以标识。

远程过程调用(Remote Procedure Call,RPC):可以用于一个进程调用另一个进程(很可能在另一个远程主机上)中的过程,从而提供了过程的分布能力。Java的RMI则在RPC的基础上向前又迈进了一步,既提供分布式对象间通讯。

二、RMI原理

2.1 工作原理图

2.2 工作原理

方法调用从客户对象经占位程序(Stub)、远程引用层(Remote Reference Layer)和传输层(Transport Layer)向下,传递给主机,然后再次经传输层,向上穿过远程调用层和骨干网(Skeleton),到达服务器对象。 占位程序扮演着远程服务器对象的代理的角色,使该对象可被客户激活。 远程引用层处理语义、管理单一或多重对象的通信,决定调用是应发往一个服务器还是多个。传输层管理实际的连接,并且追踪可以接受方法调用的远程对象。服务器端的骨干网完成对服务器对象实际的方法调用,并获取返回值。返回值向下经远程引用层、服务器端的传输层传递回客户端,再向上经传输层和远程调用层返回。最后,占位程序获得返回值。

实际上,客户端只与代表远程主机中对象的Stub对象进行通信,丝毫不知道Server的存在。客户端只是调用Stub对象中的本地方法,Stub对象是一个本地对象,它实现了远程对象向外暴露的接口,也就是说它的方法和远程对象暴露的方法的签名是相同的。客户端认为它是调用远程对象的方法,实际上是调用Stub对象中方法,可以理解为Stub对象是远程对象在本地的一个代理,当客户端调用方法的时候,Stub对象会将调用通过网络传输给远程对象。

三、RMI远程调用步骤

3.1 RMI远程调用运行流程图

3.2 RMI 远程调用步骤

  1. 客户端对象调用客户端辅助对象(Stub)上的方法。
  2. 客户端辅助对象打包调用信息(变量、方法名),通过网络发送给服务端辅助对象。
  3. 服务端辅助对象将客户端辅助对象发送来的信息解包,找出真正被调用的方法以及该方法所在对象。
  4. 调用真正服务对象上的真正方法,并将结果返回给服务端辅助对象。
  5. 服务端辅助对象将结果打包,发送给客户端辅助对象。
  6. 客户端辅助对象将返回值解包,返回给客户对象
  7. 客户对象获得返回值

四、JAVA RMI简单实现

4.1 如何实现一个RMI程序

1). 创建远程接口, 并且继承java.rmi.Remote接口。

2). 实现远程接口,并且继承:UnicastRemoteObject。

3). 创建服务器程序: createRegistry方法注册远程对象,暴露一个监听。

4). 创建客户端程序,通过ip和端口连接到指定的服务器,并且将数据做封装(序列化)

5). 服务器端收到请求,先反序列化。再进行业务逻辑处理。把返回结果序列化返回

4.2 JAVA实现RMI程序

1). 定义一个远程接口

/**
 * 必须继承Remote接口。
 * 所有参数和返回类型必须序列化(因为要网络传输)。
 * 任意远程对象都必须实现此接口。
 * 只有远程接口中指定的方法可以被调用。
 */
public interface IRemoteMath extends Remote {
    // 所有方法必须抛出RemoteException
  public double add(double a, double b) throws RemoteException;
  public double subtract(double a, double b) throws RemoteException;  
}

2). 远程接口实现类

/**
 * 服务器端实现远程接口。
 * 必须继承UnicastRemoteObject,以允许JVM创建远程的存根/代理。
 */
public class RemoteMath extends UnicastRemoteObject implements IRemoteMath {
  private int numberOfComputations;
  protected RemoteMath() throws RemoteException {
    numberOfComputations = 0;
  }
  @Override
  public double add(double a, double b) throws RemoteException {
    numberOfComputations++;
    System.out.println("Number of computations performed so far = " 
        + numberOfComputations);
    return (a+b);
  }
  @Override
  public double subtract(double a, double b) throws RemoteException {
    numberOfComputations++;
    System.out.println("Number of computations performed so far = " 
        + numberOfComputations);
    return (a-b);
  }
}

3). 服务器端

/* 注册远程对象,向客户端提供远程对象服务 
 * 远程对象是在远程服务上创建的,你无法确切地知道远程服务器上的对象的名称
 * 但是,将远程对象注册到RMI Service之后,客户端就可以通过RMI Service请求
 * 到该远程服务对象的stub了,利用stub代理就可以访问远程服务对象了
 */
public class RMIServer {
  public static void main(String[] args)  {
    try {
      IRemoteMath remoteMath = new RemoteMath();  
      LocateRegistry.createRegistry(1088);    
      Registry registry = LocateRegistry.getRegistry();
      registry.bind("Compute", remoteMath);
      System.out.println("Math server ready");
    } catch (Exception e) {
      e.printStackTrace();
    }   
  }
}

4). 客户端

public class MathClient {
  public static void main(String[] args) {
    try { 
      // 如果RMI Registry就在本地机器上,URL就是:rmi://localhost:1088/Compute
      // 否则,URL就是:rmi://RMIService_IP:1088/Compute
      Registry registry = LocateRegistry.getRegistry("localhost");        
      // 从Registry中检索远程对象的存根/代理
      IRemoteMath remoteMath = (IRemoteMath)registry.lookup("Compute");
      // 调用远程对象的方法
      double addResult = remoteMath.add(5.0, 3.0);
      System.out.println("5.0 + 3.0 = " + addResult);
      double subResult = remoteMath.subtract(5.0, 3.0);
      System.out.println("5.0 - 3.0 = " + subResult);     
    }catch(Exception e) {
      e.printStackTrace();
    }     
  } 
}


目录
相关文章
|
8月前
|
存储 缓存 Java
我们来详细讲一讲 Java NIO 底层原理
我是小假 期待与你的下一次相遇 ~
277 2
|
7月前
|
监控 Java API
现代 Java IO 高性能实践从原理到落地的高效实现路径与实战指南
本文深入解析现代Java高性能IO实践,涵盖异步非阻塞IO、操作系统优化、大文件处理、响应式网络编程与数据库访问,结合Netty、Reactor等技术落地高并发应用,助力构建高效可扩展的IO系统。
224 0
|
9月前
|
存储 缓存 Java
【高薪程序员必看】万字长文拆解Java并发编程!(5):深入理解JMM:Java内存模型的三大特性与volatile底层原理
JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm概念说明主内存所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)工作内存。
288 0
|
8月前
|
存储 算法 安全
Java中的对称加密算法的原理与实现
本文详细解析了Java中三种常用对称加密算法(AES、DES、3DES)的实现原理及应用。对称加密使用相同密钥进行加解密,适合数据安全传输与存储。AES作为现代标准,支持128/192/256位密钥,安全性高;DES采用56位密钥,现已不够安全;3DES通过三重加密增强安全性,但性能较低。文章提供了各算法的具体Java代码示例,便于快速上手实现加密解密操作,帮助用户根据需求选择合适的加密方案保护数据安全。
545 58
|
7月前
|
人工智能 安全 Java
Go与Java泛型原理简介
本文介绍了Go与Java泛型的实现原理。Go通过单态化为不同类型生成函数副本,提升运行效率;而Java则采用类型擦除,将泛型转为Object类型处理,保持兼容性但牺牲部分类型安全。两种机制各有优劣,适用于不同场景。
265 24
|
8月前
|
XML JSON Java
Java 反射:从原理到实战的全面解析与应用指南
本文深度解析Java反射机制,从原理到实战应用全覆盖。首先讲解反射的概念与核心原理,包括类加载过程和`Class`对象的作用;接着详细分析反射的核心API用法,如`Class`、`Constructor`、`Method`和`Field`的操作方法;最后通过动态代理和注解驱动配置解析等实战场景,帮助读者掌握反射技术的实际应用。内容翔实,适合希望深入理解Java反射机制的开发者。
719 13
|
7月前
|
存储 缓存 安全
深入讲解 Java 并发编程核心原理与应用案例
本教程全面讲解Java并发编程,涵盖并发基础、线程安全、同步机制、并发工具类、线程池及实际应用案例,助你掌握多线程开发核心技术,提升程序性能与响应能力。
301 0
|
8月前
|
算法 Java 索引
说一说 Java 并发队列原理剖析
我是小假 期待与你的下一次相遇 ~
|
8月前
|
安全 Java 编译器
JD-GUI,java反编译工具及原理: JavaDecompiler一个Java反编译器
Java Decompiler (JD-GUI) 是一款由 Pavel Kouznetsov 开发的图形化 Java 反编译工具,支持 Windows、Linux 和 Mac Os。它能将 `.class` 文件反编译为 Java 源代码,支持多文件标签浏览、高亮显示,并兼容 Java 5 及以上版本。JD-GUI 支持对整个 Jar 文件进行反编译,可跳转源码,适用于多种 JDK 和编译器。其原理基于将字节码转换为抽象语法树 (AST),再通过反编译生成代码。尽管程序可能带来安全风险,但可通过代码混淆降低可读性。最新版修复了多项识别错误并优化了内存管理。
6273 1