`
benx
  • 浏览: 276371 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
阅读更多
RMI(Remote Method Invocation,远程方法调用)是Java的一组拥护开发分布式应用程序的API。RMI使用Java语言接口定义了远程对象,它集合了Java序列化和Java远程方法协议(Java Remote Method Protocol)。它大大增强了Java开发分布式应用的能力。简单地说,这样使原先的程序在同一操作系统的方法调用,变成了不同操作系统之间程序的方法调用。这也就说明,RMI可以实现在不同的JVM之间执行方法的调用。由于J2EE是分布式程序平台,RMI机制实现程序组件在不同操作系统之间的通信。

下图是RMI的体系结构:



通过RMI的体系结构,已经可以看出RMI的大致工作原理:

服务器端提供服务,服务中要暴露可以调用的远程方法,以接口的形式表现,这样在客户端可以通过服务接口来调用远程方法,实现复杂的业务逻辑。在服务器端,首先要对接口中提供的方法实现,以便客户端调用能够完成一定的业务逻辑;接着需要生成Skeleton,在Skeleton中真正地实现了对商业方法的调用,完成了客户请求的调用的过程,将获取到的调用方法的结果通过序列化机制返回给客户端,进行应答。在客户端,通过Stub来接收服务器返回的数据(对象),即在这里进行了反序列化,也就是读取网络传输的字节流,进而进行重构。在Skeleton和Stub中,都对网络通信进行了处理,例如建立套接字,建立网络连接,为实际的业务需要做好准备。

可见,客户端并没有真正地执行与服务器端组件进行直接交互。

这里,有个重要的概念,就是Java对象序列化机制。序列化,就是将对象写入流,以便能够在网络上传输对象,它是输出端执行的。反序列化,也就是在接收端,为了能够获取传输的对象,需要将对象传输而来的字节流进行重构,重新得到完整的该对象。Java对象序列化的过程,是对已有的类的实例进行序列化,首先要存在一个具体的实例。

下面通过在客户端调用服务器端的方法,实现一个例子,可以很直观地模拟RMI工作,从而进一步深化对RMI工作机制的理解。我使用Oracle JDeveloper 10g开发测试。

开发过程

1、在服务接口中,将客户端可以进行调用的方法暴露给客户端。

ShirdrnService接口中列出了可以调用的方法,ShirdrnService接口如下所示:
package org.shirdrn.rmi.server;

import java.io.IOException;

public interface ShirdrnService {
    public String getServerTime() throws IOException, ClassNotFoundException;
    public String getGreetings () throws IOException, ClassNotFoundException;
}

2、在服务器端要真正实现服务接口中的这些方法,ShirdrnServiceImpl类实现了ShirdrnService接口中列出的方法。

ShirdrnServiceImpl类的实现如下所示:
package org.shirdrn.rmi.server;

import java.io.IOException;

import java.util.Date;

public class ShirdrnServiceImpl implements ShirdrnService {
    public ShirdrnServiceImpl() {
    }

    public String getServerTime() throws IOException, ClassNotFoundException{
        Date date = new Date();
        String time = date.toLocaleString();
        return time;
    }

    public String getGreetings() throws IOException, ClassNotFoundException{
        Date date = new Date();
        int hour = date.getHours();
        String greetings = "";
        if(hour < 12 && hour > 6){
            greetings = "上午好!";
        }
        else if(hour <= 18 && hour > 12){
                greetings = "下午好!";
            }
            else{
                greetings = "晚上好!";
            }
        return greetings;
    }
}

3、客户端Stub的实现

ShirdrnStub类实现了ShirdrnService接口,它是客户端获取服务结果数据最直接的实现。然而,它并没有与服务器端真正实现服务接口的实现类直接打交道,而是通过网络传输获取到调用方法的执行结果数据。
package org.shirdrn.rmi.client;

import java.io.IOException;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import java.net.Socket;

import java.net.UnknownHostException;

import org.shirdrn.rmi.server.ShirdrnService;

public class ShirdrnStub implements ShirdrnService{

    Socket socket;

    public ShirdrnStub() {
        try {
            socket = new Socket("56987b31c0b246d",8888);
        } catch (UnknownHostException e) {
            e.printStackTrace();
            System.out.println("[信息]创建套接字异常:未知的主机名称。");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public String getServerTime() throws IOException, ClassNotFoundException {
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
        oos.writeObject("getServerTime");
        oos.flush();
        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); 
        return (String)ois.readObject();
    }

    public String getGreetings() throws IOException, ClassNotFoundException {
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
        oos.writeObject("getGreetings");
        oos.flush();
        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); 
        return (String)ois.readObject();
    }
}

4、服务器端Skeleton的实现

ShirdrnSkeleton类继承了Thread,因此它可以启动服务器端线程,而且是单线程。在 ShirdrnSkeleton中,真正与提供服务实现的类进行了交互。在建立起连接以后,首先获取到客户端调用的方法,根据客户的选择来直接与服务的实现交互,执行方法获得执行结果数据,从而将结果数据进行序列化,通过网络传输给客户完成应答过程。

实例化ShirdrnSkeleton类的一个实例后,启动线程,这很像是一个服务器端监听器,监听客户端动作,从而完成服务的请求。
package org.shirdrn.rmi.server;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.net.ServerSocket;
import java.net.Socket;

public class ShirdrnSkeleton extends Thread {
    ShirdrnServiceImpl shirdrnServiceImpl;
    public ShirdrnSkeleton(ShirdrnServiceImpl shirdrnServiceImpl) {
        this.shirdrnServiceImpl = shirdrnServiceImpl;
    }
    public void run() {          
        try {
            ServerSocket serverSocket = new ServerSocket(8888);        
            Socket socket = serverSocket.accept();
            while(socket != null){
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                String method = (String)ois.readObject();
                if(method.equals("getServerTime")){
                    String serverTime = shirdrnServiceImpl.getServerTime();
                    ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                    oos.writeObject(serverTime);
                    oos.flush();
                }
                if(method.equals("getGreetings")){
                    String greetings = shirdrnServiceImpl.getGreetings();
                    ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                    oos.writeObject(greetings);
                    oos.flush();
                }
            }
        } catch (Exception e) {
           e.printStackTrace();
        }
    }
    
    public static void main(String[] args){
        ShirdrnServiceImpl ssi = new ShirdrnServiceImpl();
        ShirdrnSkeleton skeleton = new ShirdrnSkeleton(ssi);
        skeleton.start();
    }   
    
}

5、客户端测试程序

通过ShirdrnClient类中的主函数,实现了对服务器端提供的服务接口中的方法进行调用:
package org.shirdrn.rmi.client;

import java.io.IOException;

import org.shirdrn.rmi.server.ShirdrnService;

public class ShirdrnClient {
    public ShirdrnClient() {
    }

    public static void main(String[] args) throws IOException, 
                                                  ClassNotFoundException {
        ShirdrnService stub = new ShirdrnStub();
        System.out.println("正在获取服务器时间...");
        System.out.println("服务器时间 : "+stub.getServerTime());
        System.out.println("正在获取问候语...");
        System.out.println("问候语为 : "+stub.getGreetings());        
    }
}

6、测试过程


心得总结

1、客户端是直接通过实例化一个Stub,因为Stub实现了服务方暴露的接口,所以可以直接通过一个Stub的实例来调用服务方法。但是,这并没有直接调用服务方的服务接口的实现。

2、服务方具有服务接口的真正实现。而真正调用服务接口实现类是在服务器端的Skeleton中,在Skeleton中负责调用真正的服务实现,将执行结果返回给客户端,屏蔽了方法调用的实现细节。

3、客户端Stub和服务器端Skeleton之间建立起网络连接,进行了网络通信,主要就是对执行结果进行传输/接收,Skeleton将结果通过网络传输到客户端,而Stub通过代理接口接收传输而来的结果数据。
分享到:
评论

相关推荐

    RMI原理及实现

    **RMI原理及实现** 远程方法调用(Remote Method Invocation,简称RMI)是Java平台上的一个核心特性,它允许Java对象在不同的JVM之间进行交互。RMI为分布式计算提供了一个简单而强大的模型,使得开发者可以像调用...

    RMI原理及应用详解

    **RMI原理及应用详解** 远程方法调用(Remote Method Invocation,简称RMI)是Java平台提供的一种分布式计算技术,允许在不同的Java虚拟机(JVM)之间进行对象方法的透明调用。RMI的核心思想是使Java对象能够跨越...

    RMI原理.xls

    RMI原理.xls

    RMI原理及实现,ppt格式

    以下是对RMI原理和实现的详细解释: 1. **RMI的基本概念**: - RMI是Java中的一个特性,允许对象在不同的网络节点之间进行交互,执行远程对象的方法。 - RMI调用对最终用户是透明的,意味着用户无需关心方法实际...

    RMI原理详解

    本文将深入探讨RMI的工作原理、组件以及如何在实际项目中应用。 ### RMI工作原理 1. **注册与查找**:在RMI系统中,远程对象必须首先注册到一个名为远程对象注册表(Remote Object Registry)的服务,以便其他...

    rmi原理与入门demo.zip

    在“rmi原理与入门demo”这个压缩包中,你可能找到以下内容: 1. **源码示例**:包含了客户端和服务器端的Java源代码,展示了如何创建远程接口、实现远程对象、注册远程对象以及进行远程方法调用。 2. **编译与...

    rmi原理-chn-pdf

    ### RMI原理详解 #### 前言与背景 RMI(Remote Method Invocation,远程方法调用)是一种Java平台上的技术,它允许开发者在不同JVM间的对象间进行方法调用,就像是本地方法调用一样简单。这项技术的出现极大地简化...

    java_rmi.rar_RMI java_java.rmi

    Java RMI(Remote Method Invocation,远程方法调用)是Java平台提供的一种分布式计算技术,它允许Java对象在不同的网络...通过实践提供的"rmi"代码示例,你可以深入理解RMI的工作原理,并掌握如何在实际项目中使用它。

    (转)通用JAVA RMI服务器框架

    【标题】:“(转)通用JAVA RMI服务器框架” 【正文】: 在Java远程方法调用(Remote Method Invocation,RMI)技术中,构建一个...同时,深入理解RMI的工作原理和最佳实践,对于提升Java分布式编程能力非常有帮助。

    RMI原理及实现(JAVA)

    【RMI原理详解】 远程方法调用(RMI,Remote Method Invocation)是Java提供的一种用于在分布式环境中调用远程对象的方法。RMI的核心思想是使客户端可以像调用本地对象一样调用远程对象,实现这一目标的关键在于...

    RMI-IIOP 基于SUN

    这篇文章将详细介绍RMI-IIOP的基本概念、工作原理及其在实际应用中的价值。 RMI是Java中的一种机制,允许一个Java对象调用另一个在网络中不同 JVM(Java虚拟机)上运行的对象的方法。RMI-IIOP则是在RMI的基础上添加...

    java RMI 详解,实例加原理,想不理解都难

    RMI 工作原理 RMI的核心工作流程包括序列化、反序列化和远程调用代理。 - **序列化**:当客户端调用远程方法时,参数会被序列化并通过网络传输到服务器。 - **反序列化**:服务器接收到请求后,将序列化的参数反...

    java rmi java rmi

    根据提供的文件信息,我们可以深入探讨Java RMI(Java Remote Method Invocation)的相关知识点,包括其概念、原理、体系结构以及一个具体的示例。 ### RMI的概念 RMI是一种Java技术,它允许开发者创建分布式应用...

    RMI可运行的示例代码

    首先,让我们深入理解RMI的工作原理。RMI系统由两部分组成:客户端和服务器端。客户端通过接口调用远程对象的方法,而这些调用实际上被转换为网络请求,发送到服务器端。服务器端接收到请求后,执行相应的方法,并将...

    rmi_java项目实例

    本项目实例是基于RMI技术实现的一个服务器端程序,名为"RMIServer",提供了远程服务的接口和实现,下面将详细介绍RMI的基本概念、工作原理以及如何通过这个项目实例来学习和应用RMI。 1. **RMI基本概念**: - **...

    java RMI实现代码

    本项目提供的“java RMI实现代码”包括客户端和服务器端的示例,通过清晰的代码注释帮助理解RMI的工作原理。 一、RMI的基本概念 1. 远程接口:远程接口定义了客户端和服务器之间通信的API,它是Java接口,标注了`@...

    RMI

    **远程方法调用(Remote Method Invocation,RMI)** RMI是Java平台中用于实现分布式计算的一种机制。它允许一个Java对象在某台计算机上执行方法,而...了解其工作原理和最佳实践对于任何Java开发者来说都是有价值的。

    spring RMI简单例子

    在这个简单的例子中,我们将深入理解Spring RMI的工作原理以及如何实现一个基本的Spring RMI应用。 首先,让我们了解RMI的基本概念。RMI允许Java对象在不同的JVM之间进行通信,仿佛它们都在同一台机器上。它通过...

Global site tag (gtag.js) - Google Analytics