精华内容
下载资源
问答
  • Java RMI

    2019-05-17 11:09:08
    Java RMIJava远程方法调用,即Java RMIJava Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性...

    转载自: https://www.cnblogs.com/xt0810/p/3640167.html       

     

    Java RMIJava远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。

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

          RMI(Remote Method Invocation)为远程方法调用,是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。

          这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中。

    JavaRMI

    一、工作原理

          RMI能让一个Java程序去调用网络中另一台计算机的Java对象的方法,那么调用的效果就像是在本机上调用一样。通俗的讲:A机器上面有一个class,通过远程调用,B机器调用这个class 中的方法。

          RMI,远程方法调用(Remote Method Invocation)是Enterprise JavaBeans的支柱,是建立分布式Java应用程序的方便途径。RMI是非常容易使用的,但是它非常的强大。

          RMI的基础是接口,RMI构架基于一个重要的原理:定义接口和定义接口的具体实现是分开的。下面我们通过具体的例子,建立一个简单的远程计算服务和使用它的客户程序

    二、RMI包含部分:

    1. 远程服务的接口定义
    2. 远程服务接口的具体实现
    3. 桩(Stub)和框架(Skeleton)文件
    4. 一个运行远程服务的服务器
    5. 一个RMI命名服务,它允许客户端去发现这个远程服务
    6. 类文件的提供者(一个HTTP或者FTP服务器)
    7. 一个需要这个远程服务的客户端程序

    三、RMI的用途?

         RMI的用途是为分布式Java应用程序之间的远程通信提供服务,提供分布式服务。

         目前主要应用时封装在各个J2EE项目框架中,例如Spring,EJB(Spring和EJB均封装了RMI技术)

         在Spring中实现RMI:

         ①在服务器端定义服务的接口,定义特定的类实现这些接口;

         ②在服务器端使用org.springframework.remoting.rmi.RmiServiceExporter类来注册服务;

         ③在客户端使用org.springframework.remoting.rmi.RmiProxyFactoryBean来实现远程服务的代理功能;

         ④在客户端定义访问与服务器端服务接口相同的类

    四、RMI的局限?                                                                    

          RMI目前使用Java远程消息交换协议JRMP(Java Remote Messaging Protocol)进行通信。JRMP是专为Java的远程对象制定的协议,由于JRMP是专为Java对象制定的,因此,RMI对于用非Java语言开发的应用系统的支持不足。不能与用非Java语言书写的对象进行通信(意思是只支持客户端和服务器端都是Java程序的代码的远程调用)。

    五、RMI的使用局限?

          由于客户机和服务器都是使用Java编写的,二者平台兼容性的要求仅仅是双方都运行在版本兼容的Java虚拟机上。

    六、RMI调用远程方法的参数和返回值

          当调用远程对象上的方法时,客户机除了可以将原始类型的数据作为参数一外,还可以将对象作为参数来传递,与之相对应的是返回值,可以返回原始类型或对象,这些都是通过Java的对象序列化(serialization)技术来实现的。(换而言之:参数或者返回值如果是对象的话必须实现Serializable接口)

    七、 RMI应用程序的基本模型

                           

    八、RMI体系结构

     

          桩/框架(Stub/Skeleton)层:客户端的桩和服务器端的框架;

          远程引用(remote reference)层:处理远程引用行为

          传送层(transport):连接的建立和管理,以及远程对象的跟踪

    九、 RMI类和接口(完成一个简单RMI需要用到的类)。

     

     

     

    (一) Remote接口:是一个不定义方法的标记接口

          Public interface Remote{}

          在RMI中,远程接口声明了可以从远程Java虚拟机中调用的方法集。远程接口满足下列要求:

          1、远程接口必须直接或间接扩展Java.rmi.Remote接口,且必须声明为public,除非客户端于远程接口在同一包中

          2、在远程接口中的方法在声明时,除了要抛出与应用程序有关的一场之外,还必须包括RemoteException(或它的超类,IOExcepion或Exception)异常

          3、在远程方法声明中,作为参数或返回值声明的远程对象必须声明为远程接口,而非该接口的实现类。

    (二) RemoteObject抽象类实现了Remote接口和序列化Serializable接口,它和它的子类提供RMI服务器函数。

    (三) LocateRegistry final()用于获得特定主机的引导远程对象注册服务器程序的引用(即创建stub),或者创建能在特定端口接收调用的远程对象注册服务程序。

    服务器端:向其他客户机提供远程对象服务

          SomeService servcie=……;//远程对象服务

    1. Registry registry=LocateRegisty.getRegistry();//Registry是个接口,他继承了Remote,此方法返回本地主机在默认注册表端口 1099 上对远程对象 Registry 的引用。
    2. getRegistry(int port) 返回本地主机在指定 port 上对远程对象 Registry 的引用;
    3. getRegistry(String host)  返回指定 host 在默认注册表端口 1099 上对远程对象 Registry的引用;
    4. getRegistry(String host, int port) 返回指定的 host 和 port 上对远程对象 Registry 的引用
    5. registry.bind(“I serve”,service);// bind(String name,Remote obj) 绑定对此注册表中指定 name 的远程引用。name : 与该远程引用相关的名称 obj : 对远程对象(通常是一个 stub)的引用
    6. unbind(String name)移除注册表中指定name的绑定。
    7. rebind(String name,Remote obj)重新绑定,如果name已存在,但是Remote不一样则替换,如果Remote一样则丢弃现有的绑定
    8. lookup(String name) 返回注册表中绑定到指定 name 的远程引用,返回Remote
    9. String[] list()   返回在此注册表中绑定的名称的数组。该数组将包含一个此注册表中调用此方法时绑定的名称快照。

    客户机端:向服务器提供相应的服务请求。

    Registry registry=LocateRegisty.getRegistry();
    SomeService servcie=(SomeService)registry.lookup(“I serve”);
    Servcie.requestService();

    (四) Naming和Registry类类似。

    客户端:

          Naming.lookup(String url)

          url 格式如下"rmi://localhost/"+远程对象引用
    服务器端:
         Registry registry=LocateRegistry.createRegistry(int port);
         Naming.rebind(“service”,service);

    (五) RMISecurityManager

         在RMI引用程序中,如果没有设置安全管理器,则只能从本地类路径加载stub和类,这可以确保应用程序不受由远程方法调用所下载的代码侵害

         在从远程主机下载代码之前必须执行以下代码来安装RMISecurityManager:

         System.setSecurityManager(new RMISecurityManager());

    十、demo开发

         为了编写一个demo,我们分为两部分,一部分是server端的代码,一部分是client端的代码,client端的代码主要是为了使用server端的代码。当然这个代码是非常简单的,只是为了说明问题,现实的使用会使比较复杂的。

    (一) 我们的目的

         建立一个server端的java project,包含远程端的代码,定义接口,定义接口实现,然后在建立一个client端的java project,通过RMI使用远端服务中的方法。

    (二) 我们的代码结构

     

    (三) 远程服务代码

          1. 远程服务的接口定义

           第一步就是建立和编译服务接口的Java代码。这个接口定义了所有的提供远程服务的功能,下面是源程序:

           UserManagerInterface.java

    复制代码

     1 package cn.com.tt.rmiserver.stub;
     2 
     3 import java.rmi.Remote;
     4 import java.rmi.RemoteException;
     5 
     6 import cn.com.tt.rmiserver.bean.Account;
     7 
     8 public interface UserManagerInterface extends Remote{
     9     public String getUserName() throws RemoteException;
    10     public Account getAdminAccount() throws RemoteException;
    11 }

    复制代码

         接口必须继承Remote类,每一个定义地方法都要抛出RemoteException异常对象。

        2. 接口的具体实现

        第二步就是对于上面的接口进行实现:

        UserManagerImp.java

    复制代码

     1 package cn.com.tt.rmiserver;
     2 
     3 import java.rmi.RemoteException;
     4 
     5 import cn.com.tt.rmiserver.stub.UserManagerInterface;
     6 import cn.com.tt.rmiserver.bean.Account;
     7 
     8 public class UserManagerImp implements UserManagerInterface {
     9     public UserManagerImp() throws RemoteException {
    10 
    11     }
    12     private static final long serialVersionUID = -3111492742628447261L;
    13 
    14     public String getUserName() throws RemoteException{
    15         return "TT";
    16     }
    17     public Account getAdminAccount() throws RemoteException{
    18         Account account=new Account();
    19         account.setUsername("TT");
    20         account.setPassword("123456");
    21         return account;
    22     }
    23 }

    复制代码

          3. 定义一个bean,实现implements Serializable序列化接口。也就是可以在client和server端进行传输的可序列化对象。

          Account.java

    复制代码

     1 package cn.com.tt.rmiserver.bean;
     2 
     3 import java.io.Serializable;
     4 
     5 public class Account implements Serializable,Cloneable{
     6     private static final long serialVersionUID = -1858518369668584532L;
     7     private String username;
     8     private String password;
     9     
    10     public String getUsername() {
    11         return username;
    12     }
    13     public void setUsername(String username) {
    14         this.username = username;
    15     }
    16     public String getPassword() {
    17         return password;
    18     }
    19     public void setPassword(String password) {
    20         this.password = password;
    21     }
    22 }

    复制代码

          4. 定义server端的主程序入口。

              Entry.java

    复制代码

     1 package cn.com.tt.rmiserver.entry;
     2 
     3 import java.rmi.AlreadyBoundException;
     4 import java.rmi.RemoteException;
     5 import java.rmi.registry.LocateRegistry;
     6 import java.rmi.registry.Registry;
     7 import java.rmi.server.UnicastRemoteObject;
     8 
     9 import cn.com.tt.rmiserver.UserManagerImp;
    10 import cn.com.tt.rmiserver.stub.UserManagerInterface;
    11 
    12 public class Entry {
    13     public static void main(String []args) throws AlreadyBoundException, RemoteException{
    14         UserManagerImp userManager=new UserManagerImp();
    15         UserManagerInterface userManagerI=(UserManagerInterface)UnicastRemoteObject.exportObject(userManager,0);
    16         // Bind the remote object's stub in the registry
    17         Registry registry = LocateRegistry.createRegistry(2002);
    18        
    19         registry.rebind("userManager", userManagerI);
    20         System.out.println("server is ready");
    21         }
    22 }

    复制代码

    (四) client端代码

    1. 把Server端的Account类和接口UserManagerInterface 导出Export成jar包,命名为:RmiServerInterface.jar。导入到client中。
    2. 项目——右键——Export——java——jar file——next——选择Account类和接口UserManagerInterface——命名为:RmiServerInterface.jar如下图:

     

         3. 新建一个java Project,导入jar包,编写客户端代码。

        4. 代码

             ClientEntry.java

    复制代码

     1 package weiblog.rmi;
     2 
     3 import java.rmi.NotBoundException;
     4 import java.rmi.RemoteException;
     5 import java.rmi.registry.LocateRegistry;
     6 import java.rmi.registry.Registry;
     7 
     8 import cn.com.tt.rmiserver.stub.UserManagerInterface;
     9 
    10 public class ClientEntry {
    11     
    12     public static void main(String []args){
    13         
    14         try {
    15             Registry registry = LocateRegistry.getRegistry("localhost",2004);
    16             UserManagerInterface userManager = (UserManagerInterface)registry.lookup("userManager");
    17             System.out.println("用户名是"+userManager.getAdminAccount().getUsername()
    18                     +"密码"+userManager.getAdminAccount().getPassword());
    19         } catch (RemoteException e) {
    20             // TODO Auto-generated catch block
    21             e.printStackTrace();
    22         } catch (NotBoundException e) {
    23             // TODO Auto-generated catch block
    24             e.printStackTrace();
    25         }
    26         
    27     }
    28 
    29 }

    复制代码

         5. 先运行服务器端代码, 然后运行客户端代码,就会显示运行结果,客户端可以运行多次,每次都可以取得服务器端的对象。如果要再次运行客户端代码就需要更改端口号,如果不更改就会显示端口号被占用。

    展开全文
  • java rmi

    2010-12-27 09:48:00
    java rmi

    HEAD FIRST JAVA 18 分布式计算----远程部署的RMI
    --------------------------------------------------
    要点:  在某堆上的对象无法进行另外堆上的对象引用
     Java Remote Method Invocation(RMI)让你感觉上像是调用远程对象的方法.
     当客户端调用远程对象的方法时,鞋袜是调用代理上的方法,称为stub.
     stub是个处理低层网络细节的辅助性对象,它会把方法的调用包装起来送到服务器上
     要创建远程服务的话,你就必须要以远程接口来启动'
     远程接口必须要extend过java.rmi.Remote这个接口,且所有的方法都必须声明RemoteException.
     你的远程服务会实现远程接口
     远程服务应该要继承UnicasRemoteObject(技术上也有其他方法,但这最简单)
     远程服务必须要声明RemoteException的构造函数(因为父类的构造函数声明了)
     远程服务的对象必须要向RMI registry注册
     使用静态的Namin.rebind()来注册远程服务
     RMI registry必须在同一台机器上与远程服务一块执行,且必须在对象的注册之前启动
     客户端会以Naming.lookup()查询远程服务
     几乎所有与RMI有关的都会抛出RemoteException(由编译器检查)

     调用方法的过程:
      1.客户端对象对辅助设施对象调用doBigThing()
      2.客户端辅助设施把调用信息打包通过网络送到服务器的辅助设施
      3.服务端的辅助设施解开来自客户端辅助设施的信息,并以此调用真正的服务

     在RMI中,客户端的辅助设施称为stub,而服务器端的辅助设施称为skeleton

     别忘记客户端是使用接口来调用stub上的方法,客户端的Java虚拟机必须要有stub类,但客户端不会在程序代码中引用到stub类,客户端总是通过接口来操作真正的远程对象.
     服务器上必须要有stub和skeleton,以及服务与远程的接口,它会需要stub类是因为stub会被代换成连接在RMI registry上真正的服务.
    -------------------------------------------
    程序代码 :

    创建远程服务:
    1.创建Remote接口
    import java.rmi.*  //Remote在java.rmi中

    public interface MyRemote extends Remote{
     //声明所有的方法都会抛出RemoteException
     //返回值会通过网络传送,所以必须是Serializable.参数和返回值都是这样打包 //传送的
     public String sayHello() throws RemoteException;
    }

    2.实现Remote
    public class MyRemoteImp1 extends UnicastRemoteObject implements MyRemote{
     public String sayHello(){
      return "Server says,'Hey'";
     }
     //more code in class
    }

    //声明RemoteException的无参数构造函数
    public MyRemoteImp1() throws RemoteException{}

    向RMI registry注册服务
    try{
     MyRemote service=new MyRemoteImp1();
     //帮服务命名(客户端会靠名字查询registry),并向RMI registry注册,RMI会将 //stub做交换并把stub加入registry
     Naming.rebind("Remote Hello",service);
    }catch(Exception ex) { ...}

    3.用rmic产生stub与skeleton
    4.启动RMI registry(rmiregistry)
    5.启动远程服务

    ----
    完整的程序代码
    Remote interface:

    import java.rmi.*;

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

    Remote service(实现):

    import java.rmi.*;
    import java.rmi.server.*; //UnicastRemoteObject是在这个包中

    public class MyRemoteImp1 extends UnicastRemoteObject implements MyRemote{
     public String sayHello(){
      return"Server says,'Hey'";
     }

     public MyRemoteImp1() throws RemoteException{  }
     
     public static void main(String[] args){
      try{
       MyRemote service=new MyRemoteImp1();
     
       Naming.rebind("Remote Hello",service);
      }catch(Exception ex) {ex.printStackTrace();}
     }
    }
    --------------
    客户端如何取得stub对象
    MyRemote service=(MyRemote) Naming.lookup("rmi://127.0.0.1/Remote Hello");
    //必须要转换成接口的类型因为查询结果会是Object类型

    用户如何取得stub的类
    完整的客户端程序代码:
    import java.rmi.*;

    public class MyRemoteClient{
     public static void main(String[] args){
      new MyRemoteClient().go();
     }

     public void go(){
      try{
       MyRemote service=(MyRemote) Naming.lookup("rmi://127.0.0.1/Remote Hello");

       String s = service.sayHello();

       System.out.println(s);
      }catch(Exception ex) {ex.printStackTrace();}
     }
    }

    ----------------
    使用RMI时程序员最常犯的三个错误:
    1.忘记在启动远程服务前启动rmiregistry(使用Naming.rebind()注册服务前rmiregistry必须启动)
    2.忘记把参数和返回类型做成可序列化(编译器不会检测到,执行时才会发现)
    3.忘记将stub类交给客户端

    展开全文
  • java RMI

    2016-10-27 20:02:00
    JavaRMI(RemoteMethodInvocation远程方法调用)是用Java在JDK1.1中实现的,它大大增强了Java开发分布式应用的能力。Java作为一种风靡一时的网络开发语言,其巨大的威力就体现在它强大的开发分布式网络应用的能力上...

    Java RMI (Remote Method Invocation 远程方法调用)是用Java在JDK1.1中实现的,它大大增强了Java开发分布式应用的能力。Java作为一种风靡一时的网络开发语言,其巨大的威力就体现在它强大的开发分布式网络应用的能力上,而RMI就是开发百分之百纯Java的网络分布式应用系统的核心解决方案之一。其实它可以被看作是RPC的Java版本。但是传统RPC并不能很好地应用于分布式对象系统。而Java RMI 则支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。RMI目前使用Java远程消息交换协议JRMP(Java Remote Messaging Protocol)进行通信。JRMP是专为Java的远程对象制定的协议。因此,Java RMI具有Java的"Write Once, Run Anywhere"的优点,是分布式应用系统的百分之百纯Java解决方案。用Java RMI开发的应用系统可以部署在任何支持JRE(Java Run Environment Java,运行环境)的平台上。但由于JRMP是专为Java对象制定的,因此,RMI对于用非Java语言开发的应用系统的支持不足。不能与用非Java语言书写的对象进行通信。本文拟从程序的角度举例介绍怎样利用RMI实现Java分布式应用。 

     

    一、RMI系统运行机理

    RMI应用程序通常包括两个独立的程序:服务器程序和客户机程序。典型的服务器应用程序将创建多个远程对象,使这些远程对象能够被引用,然后等待客户机调用这些远程对象的方法。而典型的客户机程序则从服务器中得到一个或多个远程对象的引用,然后调用远程对象的方法。RMI为服务器和客户机进行通信和信息传递提供了一种机制。

    在与远程对象的通信过程中,RMI使用标准机制:stub和skeleton。远程对象的stub担当远程对象的客户本地代表或代理人角色。调用程序将调用本地stub的方法,而本地stub将负责执行对远程对象的方法调用。在RMI中,远程对象的stub与该远程对象所实现的远程接口集相同。调用stub的方法时将执行下列操作:

    (1)初始化与包含远程对象的远程虚拟机的连接;

    (2)对远程虚拟机的参数进行编组(写入并传输);

    (3)等待方法调用结果;

    (4)解编(读取)返回值或返回的异常;

    (5)将值返回给调用程序。

    为了向调用程序展示比较简单的调用机制,stub将参数的序列化和网络级通信等细节隐藏了起来。在远程虚拟机中,每个远程对象都可以有相应的skeleton(在JDK1.2环境中无需使用skeleton)。Skeleton负责将调用分配给实际的远程对象实现。它在接收方法调用时执行下列操作:

    (1)解编(读取)远程方法的参数;

    (2)调用实际远程对象实现上的方法;

    (3)将结果(返回值或异常)编组(写入并传输)给调用程序。stub和skeleton由rmic编译器生成。

     

    利用RMI编写分布式对象应用程序需要完成以下工作:

    (1)定位远程对象。应用程序可使用两种机制中的一种得到对远程对象的引用。它既可用RMI的简单命名工具rmiregistry来注册它的远程对象,也可以将远程对象引用作为常规操作的一部分来进行传递和返回。

    (2)与远程对象通信。远程对象间通信的细节由RMI处理,对于程序员来说,远程通信看起来就像标准的Java方法调用。

    (3)给作为参数或返回值传递的对象加载类字节码。因为RMI允许调用程序将纯Java对象传给远程对象,所以,RMI将提供必要的机制,既可以加载对象的代码又可以传输对象的数据。在RMI分布式应用程序运行时,服务器调用注册服务程序以使名字与远程对象相关联。客户机在服务器上的注册服务程序中用远程对象的名字查找该远程对象,然后调用它的方法。

     

    二、对象序列化

    在RMI分布式应用系统中,服务器与客户机之间传递的Java对象必须是可序列化的对象。不可序列化的对象不能在对象流中进行传递。对象序列化扩展了核心Java输入/输出类,同时也支持对象。对象序列化支持把对象编码以及将通过它们可访问到的对象编码变成字节流;同时,它也支持流中对象图形的互补重构造。序列化用于轻型持久性和借助于套接字或远程方法调用(RMI)进行的通信。序列化中现在包括一个 API(Application Programming Interface,应用程序接口),允许独立于类的域指定对象的序列化数据,并允许使用现有协议将序列化数据域写入流中或从流中读取,以确保与缺省读写机制的兼容性。

    为编写应用程序,除多数瞬态应用程序外,都必须具备存储和检索 Java对象的能力。以序列化方式存储和检索对象的关键在于提供重新构造该对象所需的足够对象状态。存储到流的对象可能会支持 Serializable(可序列化)或 Externalizable(可外部化)接口。对于Java对象,序列化形式必须能标识和校验存储其内容的对象所属的 Java类,并且将该内容还原为新的实例。对于可序列化对象,流将提供足够的信息将流的域还原为类的兼容版本。对于可外部化对象,类将全权负责其内容的外部格式。序列化 Java 对象的目的是:提供一种简单但可扩充的机制,以序列化方式维护 Java对象的类型及安全属性;具有支持编组和解编的扩展能力以满足远程对象的需要;具有可扩展性以支持 Java 对象的简单持久性;只有在自定义时,才需对每个类提供序列化自实现;允许对象定义其外部格式。

     

    三、分布式应用的实现和运行步骤

    Java远程方法调用(RMI)提供了Java程序语言的远程通讯功能,这种特性使客户机上运行的程序可以调用远程服务器上的对象,使Java编程人员能够在网络环境中分布操作。创建一个简单的Java分布式远程方法调用程序可以按以下几个步骤操作:

     

    (1)定义远程接口

    在 Java 中,远程对象是实现远程接口的类的实例,远程接口声明每个要远程调用的方法。在需要创建一个远程对象的时候,我们通过传递一个接口来隐藏基层的实施细节,客户通过接口句柄发送消息即可。远程接口具有如下特点:

    1、远程接口必须为public属性。如果不这样,除非客户端与远程接口在同一个包内,否则当试图装入实现该远程接口的远程对象时,调用会得到错误结果。

    2、远程接口必须扩展接口java.rmi.Remote。

    3、除与应用程序本身特定的例外之外,远程接口中的每个方法都必须在自己的throws从句中 声明java.rmi.RemoteException。(或RemoteException 的父类)。

    4、作为参数或返回值传递的一个远程对象(不管是直接,还是本地对象中嵌入)必须声明为远程接口,而不应声明为实施类。

    下面是远程接口的接口RmiSample的定义:

     

     

    [java] view plain copy
     
    1. package com.rim.demo;  
    2.   
    3. import java.rmi.Remote;  
    4. import java.rmi.RemoteException;  
    5.   
    6. public interface RmiSample extends Remote  
    7. {  
    8.     public int sum(int a, int b) throws RemoteException;  
    9. }  

     

     

    (2)实现远程接口

    远程对象实现类必须扩展远程对象java.rmi.UnicastRemoteObject类,并实现所定义的远程接口。远程对象的实现类中包含实现每个远程接口所指定的远程方法的代码。这个类也可以含有附加的方法,但客户只能使用远程接口中的方法。因为客户是指向接口的一个句柄,而不是它的哪个类。必须为远程对象定义构造函数,即使只准备定义一个默认构造函数,用它调用基础类构造函数。因为基础类构造函数可能会抛出 java.rmi.RemoteException,所以即使别无它用必须抛出java.rmi.RemoteException例外。以下是远程对象实现类的声明:

    [java] view plain copy
     
    1. package com.rim.demo;  
    2.   
    3. import java.rmi.RemoteException;  
    4. import java.rmi.server.UnicastRemoteObject;  
    5.   
    6. public class RmiSampleImpl extends UnicastRemoteObject implements RmiSample  
    7. {  
    8.     private static final long serialVersionUID = 1L;  
    9.   
    10.     protected RmiSampleImpl() throws RemoteException  
    11.     {  
    12.         super();  
    13.     }  
    14.   
    15.     public int sum(int a, int b)  
    16.     {  
    17.         return a + b;  
    18.     }  
    19. }  

     

     

    (3)编写服务器类

    包含 main 方法的类可以是实现类自身,也可以完全是另一个类。下面通过RmiSampleServer 来创建一个远程对象的实例,并通过java.rmi.registry.LocateRegistry类的createRegistry 方法从指定端口号启动注册服务程序,也可以通过执行 rmiregistry 命令启动注册服务程序,注册服务程序的缺省运行端口为 1099。必须将远程对象名字绑定到对远程对象的引用上: Naming.rebind("//localhost:8808/SAMPLE-SERVER" , Server);。以下是服务器类的声明:

     

    [java] view plain copy
     
    1. package com.rim.demo;  
    2.   
    3. import java.NET.MalformedURLException;  
    4. import java.rmi.Naming;  
    5. import java.rmi.RemoteException;  
    6. import java.rmi.registry.LocateRegistry;  
    7.   
    8. public class RmiSampleServer  
    9. {  
    10.     public static void main(String[] args)  
    11.     {  
    12.         try  
    13.         {  
    14.             LocateRegistry.createRegistry(8808);  
    15.             RmiSampleImpl server = new RmiSampleImpl();  
    16.             Naming.rebind("//localhost:8808/SAMPLE-SERVER", server);  
    17.         }  
    18.         catch (RemoteException e)  
    19.         {  
    20.             e.printStackTrace();  
    21.         }  
    22.         catch (MalformedURLException e)  
    23.         {  
    24.             e.printStackTrace();  
    25.         }  
    26.     }  
    27. }  

     

    (4)编写使用远程服务的客户机类

    客户机类的主要功能有两个,一是通过Naming.lookup方法来构造注册服务程序 stub 程序实例,二是调用服务器远程对象上的远程方法。以下是服务器类的声明:

     

    [java] view plain copy
     
    1. package com.rim.demo;  
    2.   
    3. import java.rmi.Naming;  
    4. import java.rmi.RemoteException;  
    5.   
    6. public class RmiSampleClient  
    7. {  
    8.     public static void main(String[] args)  
    9.     {  
    10.         try  
    11.         {  
    12.             String url = "//localhost:8808/SAMPLE-SERVER";  
    13.             RmiSample RmiObject = (RmiSample) Naming.lookup(url);  
    14.             System.out.println(" 1 + 2 = " + RmiObject.sum(1, 2));  
    15.         }  
    16.         catch (RemoteException rex)  
    17.         {  
    18.             System.out.println("Error in lookup: " + rex.toString());  
    19.         }  
    20.         catch (java.net.MalformedURLException me)  
    21.         {  
    22.             System.out.println("Malformed URL: " + me.toString());  
    23.         }  
    24.         catch (java.rmi.NotBoundException ne)  
    25.         {  
    26.             System.out.println("NotBound: " + ne.toString());  
    27.         }  
    28.     }  
    29. }  

     

    (5)编译代码

    要编译 Java 源文件,请运行 javac 命令:

    javac RmiSample.Java RmiSampleImpl.java RmiSampleServer.java RmiSampleClient.java

     

    (6)为远程对象实现创建根和干:

    要创建存根程序和骨架文件,应以包含远程对象实现的已编译类包全名运行 rmic 编译器。

    存根(Stub)是远程对象在客户端的代理,它将RMI调用传递给服务器端的骨架(Skeleton),后者负责将该调用传递给实际的远程方法输入如下:

    D:/RMI>rmic -d D:/RMI RmiSampleImpl 执行这个命令, 若rmic成功运行,RMI目录下就会多出两个新类: RmiSampleImpl_Stub.class RmiSampleImpl_Skel.class 它们分别对应的是存根(stub)和骨架(skeleton)。

     

    (7)运行代码:

    运行服务端程序:在Windows下,输入下列命令,在后台启动RmiSampleServer程序:

    D:/RMI>java RmiSampleServer

    运行客户端程序:

    D:/RMI>java RmiSampleClient

    客户端输出: 1 + 2 = 3

     

    转载于:https://www.cnblogs.com/Evil-Rebe/p/6005372.html

    展开全文
  • java rmi_Java RMI

    2020-07-30 00:03:34
    java rmi Java RMI (Java RMI) Remote method invocation(RMI) allow a java object to invoke method on an object running on another machine. RMI provide remote communication between java program. RMI is ...

    java rmi

    Remote method invocation(RMI) allow a java object to invoke method on an object running on another machine. RMI provide remote communication between java program. RMI is used for building distributed application.

    远程方法调用(RMI)允许java对象在另一台计算机上运行的对象上调用方法。 RMI提供Java程序之间的远程通信。 RMI用于构建分布式应用程序。

    RMI应用程序的概念 (Concept of RMI application)

    A RMI application can be divided into two part,Client program and Server program. A Server program creates some remote object, make their references available for the client to invoke method on it. A Client program make request for remote objects on server and invoke method on them. Stub and Skeleton are two important object used for communication with remote object.

    RMI应用程序可以分为两部分, 客户端程序和服务器程序。 Server程序创建一些远程对象,使它们的引用可供客户端在其上调用方法。 客户端程序在服务器上请求远程对象,并在它们上调用方法。 存根骨架是用于与远程对象通信的两个重要对象。

    存根 (Stub)

    In RMI, a stub is an object that is used as a Gateway for the client-side. All the outgoing request are sent through it. When a client invokes the method on the stub object following things are performed internally:

    在RMI中,存根是一个对象,用作客户端的网关。 所有外发请求都通过它发送。 当客户端在存根对象上调用该方法时,将在内部执行以下操作:

    1. A connection is established using Remote Virtual Machine.

      使用远程虚拟机建立连接。

    2. It then transmits the parameters to the Remote Virtual Machine. This is also known as Marshals

      然后,它将参数传输到远程虚拟机。 这也称为法警

    3. After the 2nd step, it then waits for the output.

      在第二步之后,然后等待输出。

    4. Now it reads the value or exception which is come as an output.

      现在,它读取作为输出来的值或异常。

    5. At last, it returns the value to the client.

      最后,它将值返回给客户端。

    骨架 (Skeleton)

    In RMI, a skeleton is an object that is used as a Gateway for the server-side.All the incoming request are sent through it. When a Server invokes the method on the skeleton object following things are performed internally:

    在RMI中,框架是一个对象,用作服务器端的网关,所有传入的请求都通过它发送。 当服务器在骨架对象上调用该方法时,将在内部执行以下操作:

    1. All the Parameters are read for the remote method.

      读取所有参数以用于远程方法。

    2. The method is invoked on the remote object.

      该方法在远程对象上调用。

    3. It then writes and transmits the parameters for the result. This is also known as Marshals.

      然后,它为结果写入并传输参数。 这也称为法警。

    RMI application

    存根和骨架 (Stub and Skeleton)

    Stub act as a gateway for Client program. It resides on Client side and communicate with Skeleton object. It establish the connection between remote object and transmit request to it.

    存根充当客户端程序的网关。 它位于客户端,并与Skeleton对象通信。 它建立远程对象之间的连接并向其发送请求。

    RMI application

    Skeleton object resides on server program. It is responsible for passing request from Stub to remote object.

    骨架对象驻留在服务器程序上。 它负责将请求从存根传递到远程对象。

    创建一个简单的RMI应用程序涉及以下步骤 (Creating a Simple RMI application involves following steps)

    • Define a remote interface.

      定义一个远程接口。

    • Implementing remote interface.

      实现远程接口。

    • create and start remote application

      创建并启动远程应用程序

    • create and start client application

      创建并启动客户端应用程序

    定义一个远程接口 (Define a remote interface)

    A remote interface specifies the methods that can be invoked remotely by a client. Clients program communicate to remote interfaces, not to classes implementing it. To be a remote interface, a interface must extend the Remote interface of java.rmi package.

    远程接口指定客户端可以远程调用的方法。 客户端程序与远程接口通信,而不是与实现它的类通信。 要成为远程接口,接口必须扩展java.rmi包的Remote接口。

    import java.rmi.*;
    public interface AddServerInterface extends Remote
    {
    public int sum(int a,int b);
    }

    远程接口的实现 (Implementation of remote interface)

    For implementation of remote interface, a class must either extend UnicastRemoteObject or use exportObject() method of UnicastRemoteObject class.

    为了实现远程接口,类必须扩展UnicastRemoteObject或使用UnicastRemoteObject类的exportObject()方法。

    import java.rmi.*;
    import java.rmi.server.*;
    public class Adder extends UnicastRemoteObject implements AddServerInterface
    {
    	Adder()throws RemoteException{
    	super();
    }
    public int sum(int a,int b)
    {
    	return a+b;
    }
    }

    创建AddServer并托管rmi服务 (Create AddServer and host rmi service)

    You need to create a server application and host rmi service Adder in it. This is done using rebind() method of java.rmi.Naming class. rebind() method take two arguments, first represent the name of the object reference and second argument is reference to instance of Adder

    您需要创建一个服务器应用程序并在其中托管rmi服务Adder 。 这是使用java.rmi.Naming类的rebind()方法完成的。 rebind()方法rebind()两个参数,第一个表示对象引用的名称,第二个参数是对Adder实例的引用

    import java.rmi.*;
    import java.rmi.registry.*;
    public class AddServer {
    	public static void main(String args[]) {
    		try {
    			AddServerInterface addService=new Adder();
    			Naming.rebind("AddService",addService);	//addService object is hosted with name AddService
    
    		}
    		catch(Exception e) {
    			System.out.println(e);
    		}
    	}
    }

    创建客户端应用程序 (Create client application)

    Client application contains a java program that invokes the lookup() method of the Naming class. This method accepts one argument, the rmi URL and returns a reference to an object of type AddServerInterface. All remote method invocation is done on this object.

    客户端应用程序包含一个Java程序,该程序调用Naming类的lookup()方法。 此方法接受一个参数rmi URL,并返回对类型AddServerInterface的对象的引用 。 所有远程方法调用都在此对象上完成。

    import java.rmi.*;
    public class Client {
    	public static void main(String args[]) {
    		try{
    			AddServerInterface st = (AddServerInterface)Naming.lookup("rmi://"+args[0]+"/AddService");
    			System.out.println(st.sum(25,8));
    		}
    		catch(Exception e) {
    			System.out.println(e);
    		}
    	}
    }

    运行此RMI应用程序的步骤 (Steps to run this RMI application)

    Save all the above java file into a directory and name it as "rmi"

    将上述所有Java文件保存到目录中,并将其命名为“ rmi”

    • compile all the java files

      编译所有的java文件

      javac *.java
      
      run rmi application
    • Start RMI registry

      启动RMI注册表

      start rmiregistry
      
      run rmi application
    • Run Server file

      运行服务器文件

      java AddServer
      
      run rmi application
    • Run Client file in another command prompt abd pass local host port number at run time

      在另一个命令提示符下运行客户端文件,在运行时Abd通过本地主机端口号

      java Client 127.0.0.1
      
      run rmi application

    例: (Example:)

    Program: Power.java

    程序:Power.java

    import java.rmi.*;  
    public interface Power extends Remote
    {  
    	public int power1()throwsRemoteException;  
    }

    Program: PowerRemote.java

    程序:PowerRemote.java

    import java.rmi.*;  
    import java.rmi.server.*; 
    import java.util.Scanner; 
    public class PowerRemote extends UnicastRemoteObject implements Power
    {  
    PowerRemote()throws RemoteException
    {  
    	super();  
    }  
    public int power1(int z)
    {
    int z;
    Scanner sc = new Scanner(System.in);
    System.out.println("Enter the base number ::");
    int x = sc.nextInt();
    System.out.println("Enter the exponent number ::");
    int y = sc.nextInt();
                   z=y^x;
    System.out.println(z);
    }  
    }

    MyServer.java

    MyServer.java

    import java.rmi.*;  
    import java.rmi.registry.*;  
    public class MyServer
    {  
    public static void main(String args[])
    {  
    try
    {  
    Power stub=new PowerRemote();  
    Naming.rebind("rmi://localhost:1995/shristee",stub);  
    }
    catch(Exception e)
    {
    System.out.println(e);
    }  
    }  
    }

    MyClient.java

    MyClient.java

    import java.rmi.*;  
    public class MyClient
    {  
    public static void main(String args[])
    {  
    try
    {  
    Power stub=(Power)Naming.lookup("rmi://localhost:1995/shristee");  
    System.out.println(stub.power1());  
    }
    catch(Exception e){}  
    }  
    }
    example-stub-and-skeleton

    翻译自: https://www.studytonight.com/java/rmi-in-java.php

    java rmi

    展开全文
  • JAVA RMI

    2019-04-07 01:00:31
    NULL 博文链接:https://ryxxlong.iteye.com/blog/1560535
  • java rmi与dubbo

    千次阅读 多人点赞 2019-07-31 19:17:07
    首先得知道什么是分布式,以及和集群的区别? 分布式:一个业务分拆成多个子业务,部署在不同的服务器上,多半是为了业务解耦,不同...RMI(Remote Method Invocation)即远程方法调用,是java在JDK1.1中实现的一...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,021
精华内容 4,408
关键字:

javarmi

java 订阅