Java之——RMI远程过程调用(插曲)

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/45970641

一、定义

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

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

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

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

二、工作原理

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

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

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

三、RMI包含部分

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

四、用途

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虚拟机上。

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

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

八、RMI应用程序的基本类型

九、RMI体系结构

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

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

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

十、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=……;//远程对象服务

Registry registry=LocateRegisty.getRegistry();//Registry是个接口,他继承了Remote,此方法返回本地主机在默认注册表端口 1099 上对远程对象Registry 的引用。getRegistry(int port) 返回本地主机在指定 port 上对远程对象 Registry 的引用;getRegistry(String host)  返回指定host 在默认注册表端口 1099 上对远程对象Registry
的引用;getRegistry(String host, int port) 返回指定的hostport 上对远程对象 Registry 的引用registry.bind(“I serve”,service);// bind(String name,Remote obj) 绑定对此注册表中指定 name 的远程引用。name : 与该远程引用相关的名称 obj : 对远程对象(通常是一个 stub)的引用unbind(String name)移除注册表中指定name的绑定。rebind(String name,Remote obj)重新绑定,如果name已存在,但是Remote不一样则替换,如果Remote一样则丢弃现有的绑定lookup(String name)
返回注册表中绑定到指定 name 的远程引用,返回RemoteString[] 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,我们分为两部分,一部分是server端的代码,一部分是client端的代码,client端的代码主要是为了使用server端的代码。当然这个代码是非常简单的,只是为了说明问题,现实的使用会使比较复杂的。

(一) 我们的目的

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

(二) 我们的代码结构

(三) 远程服务代码

1. 远程服务的接口定义

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

UserManagerInterface.java

  package cn.com.tt.rmiserver.stub;
  import java.rmi.Remote;
  import java.rmi.RemoteException;
  import cn.com.tt.rmiserver.bean.Account;
  /**
   *  author liuyazhuang
   */
  public interface UserManagerInterface extends Remote{
      public String getUserName() throws RemoteException;
     public Account getAdminAccount() throws RemoteException;
 }

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

2. 接口的具体实现

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

UserManagerImp.java

  package cn.com.tt.rmiserver;

  import java.rmi.RemoteException;

  import cn.com.tt.rmiserver.stub.UserManagerInterface;
  import cn.com.tt.rmiserver.bean.Account;
  /**
   *  author liuyazhuang
   */
  public class UserManagerImp implements UserManagerInterface {
      public UserManagerImp() throws RemoteException {

     }
     private static final long serialVersionUID = -3111492742628447261L;

     public String getUserName() throws RemoteException{
         return "TT";
     }
     public Account getAdminAccount() throws RemoteException{
         Account account=new Account();
         account.setUsername("TT");
         account.setPass<a href="http://www.it165.net/edu/ebg/" target="_blank" class="keylink">word</a>("123456");
         return account;
     }
 }
3. 定义一个bean

实现implements Serializable序列化接口。也就是可以在client和server端进行传输的可序列化对象。

Account.java

  package cn.com.tt.rmiserver.bean;

  import java.io.Serializable;
  /**
   *  @author liuyazhuang
   */
  public class Account implements Serializable,Cloneable{
      private static final long serialVersionUID = -1858518369668584532L;
      private String username;
      private String pass<a href="http://www.it165.net/edu/ebg/" target="_blank" class="keylink">word</a>;

     public String getUsername() {
         return username;
     }
     public void setUsername(String username) {
         this.username = username;
     }
     public String getPassword() {
         return password;
     }
     public void setPassword(String password) {
         this.password = password;
     }
 }
4. 定义server端的主程序入口。

Entry.java

  package cn.com.tt.rmiserver.entry;

  import java.rmi.AlreadyBoundException;
  import java.rmi.RemoteException;
  import java.rmi.registry.LocateRegistry;
  import java.rmi.registry.Registry;
  import java.rmi.server.UnicastRemoteObject;

  import cn.com.tt.rmiserver.UserManagerImp;
  import cn.com.tt.rmiserver.stub.UserManagerInterface;
  /**
   * @author liuyazhuang
   */
  public class Entry {
     public static void main(String []args) throws AlreadyBoundException, RemoteException{
         UserManagerImp userManager=new UserManagerImp();
         UserManagerInterface userManagerI=(UserManagerInterface)UnicastRemoteObject.exportObject(userManager,0);
         // Bind the remote object's stub in the registry
         Registry registry = LocateRegistry.createRegistry(2002);

         registry.rebind("userManager", userManagerI);
         System.out.println("server is ready");
         }
 }

(四) client端代码

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

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

ClientEntry.java

  package weiblog.rmi;

  import java.rmi.NotBoundException;
  import java.rmi.RemoteException;
  import java.rmi.registry.LocateRegistry;
  import java.rmi.registry.Registry;

  import cn.com.tt.rmiserver.stub.UserManagerInterface;
  /**
   *  @author liuyazhuang
   */
  public class ClientEntry {

     public static void main(String []args){

         try {
             Registry registry = LocateRegistry.getRegistry("localhost",2004);
             UserManagerInterface userManager = (UserManagerInterface)registry.lookup("userManager");
             System.out.println("用户名是"+userManager.getAdminAccount().getUsername()
                     +"密码"+userManager.getAdminAccount().getPassword());
         } catch (RemoteException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         } catch (NotBoundException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }

     }

 }
7. 先运行服务器端代码, 然后运行客户端代码

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

时间: 2024-10-05 15:00:24

Java之——RMI远程过程调用(插曲)的相关文章

Java中RMI远程调用demo

Java远程方法调用,即Java RMI(Java Remote Method Invocation),一种用于实现远程过程调用的应用程序编程接口.它使客户机上运行的程序可以调用远程服务器上的对象.远程方法调用特性使Java编程人员能够在网络环境中分布操作.RMI全部的宗旨就是尽可能简化远程接口对象的使用. Java RMI极大地依赖于接口.在需要创建一个远程对象的时候,程序员通过传递一个接口来隐藏底层的实现细节.客户端得到的远程对象句柄正好与本地的根代码连接,由后者负责透过网络通信.这样一来,

Java之RMI(远程方法调用)

RMI(Remote Method Invocation)中文名称是远程方法调用,可用于分布式计算. 这里就不去详细介绍RMI了,本Blog主要讲叙RMI实战和有哪些需要注意的地方,如果想要查看详细介绍请查看:百度百科RMI RMI分为服务端和客户端 服务端: 创建服务端: LocateRegistry.createRegistry(端口); Naming.rebind("rmi://IP地址:端口/RMI服务名称",RMI服务对象);//rebind也可以用bind替代 示例: Lo

Java的RMI远程方法调用实现和应用

最近在学习Dubbo,RMI是很重要的底层机制,RMI(Remote Method Invocation)远程方法调用是一种计算机之间利用远程对象互相调用实现双方通讯的一种通讯机制.使用这种机制,某一台计算机(即JVM虚拟机)上的对象可以调用另外一台计算机上的对象来获取远程数据. RMI的实现对建立分布式Java应用程序至关重要,是Java体系非常重要的底层技术. 1.RMI的概念和原理 RMI思路是在客户端安装一个代理(proxy),代理是位于客户端虚拟机中的一个对象,对于客户端对象,看起来就

关于&lt;Java 中 RMI、JNDI、LDAP、JRMP、JMX、JMS那些事儿(上)&gt;看后的一些总结-1

原文地址:https://www.anquanke.com/post/id/194384#h3-3 1.java rmi 关于rmi客户端和服务端通信的过程,java的方法都实现在rmi服务端,客户端实际上是通过访问rmi注册表拿到stub,然后再通过它调用服务端方法,那么调用方法时要传递参数,参数可以为一般类型,也可以为引用类型,那么如果为引用类型,就能够利用服务端已经有的gaget chain来打server,因为参数实际上是序列化传输的,那么数据到达服务端后必定会经过反序列化. 客户端:

java RMI入门指南

感觉这篇文章不错,直接转了 RMI全称是Remote Method Invocation-远程方法调用,Java RMI在JDK1.1中实现的,其威力就体如今它强大的开发分布式网络应用的能力上,是纯Java的网络分布式应用系统的核心解决方式之中的一个.事实上它能够被看作是RPC的Java版本号.可是传统RPC并不能非常好地应用于分布式对象系统.而Java RMI 则支持存储于不同地址空间的程序级对象之间彼此进行通信.实现远程对象之间的无缝远程调用. RMI眼下使用Java远程消息交换协议JRMP

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

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

Java RMI 介绍和例子以及Spring对RMI支持的实际应用实例

RMI 相关知识 RMI全称是Remote Method Invocation-远程方法调用,Java RMI在JDK1.1中实现的,其威力就体现在它强大的开发分布式网络应用的能力上,是纯Java的网络分布式应用系统的核心解决方案之一.其实它可以被看作是RPC的Java版本.但是传统RPC并不能很好地应用于分布式对象系统.而Java RMI 则支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用. RMI目前使用Java远程消息交换协议JRMP(Java Remot

java 对象序列化 RMI

对于一个存在于Java虚拟机中的对象来说,其内部的状态只保持在内存中.JVM停止之后,这些状态就丢失了.在很多情况下,对象的内部状态是需要被持久化下来的.提到持久化,最直接的做法是保存到文件系统或是数据库之中.这种做法一般涉及到自定义存储格式以及繁琐的数据转换.对象关系映射(Object-relational mapping)是一种典型的用关系数据库来持久化对象的方式,也存在很多直接存储对象的对象数据库.对象序列化机制(object serialization)是Java语言内建的一种对象持久化

对JAVA RMI的认识

RMI的定义 RPC (Remote Procedure Call):远程方法调用,用于一个进程调用另一个进程中的过程,从而提供了过程的分布能力. RMI(Remote Method Invocation):远程方法调用,即在RPC的基础上有向前迈进了一步,提供分布式对象间的通讯.允许运行在一个java 虚拟机的对象调用运行在另一个java虚拟机上对象的方法.这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中. RMI的全称宗旨就是尽量简化远程接口对象的调用.