java rmi

来源:互联网 发布:360浏览器优化版 编辑:程序博客网 时间:2024/05/21 12:58

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类交给客户端

原创粉丝点击