2007年5月25日星期五

Java RMI 极速攻略

回家作业上要用到RMI,这两天抽了点时间学习了一下,感觉上手还算简单,但有些设置之类的时间长了怕记不住,因此花点时间写了这个入门攻略。

---------------------------------

RMI简介

RMI就是Remote Method Invocation,类似与RPC。 它的原理同CORBA, DCOM,.net remoting相似,但是比他们要简单很多。详细的介绍可以看参考资料部分的[SUN公司的RMI教程]http://java.sun.com/developer/onlineTraining/rmi/RMI.html

实做

下面分几步来完成一个简单例子----login(这个功能用的快烂了)

想法是,server端程序提供接口方法login,接收两个参数,用户名和密码,为了简单起见,我们直接返回true。在client端调用server端的方法,看看是否能够顺利返回true。

该程序没有任何意义,仅仅用于演示RMI的开发过程。

1. 定义远程接口

远程接口如下:(ICustomer.java)

import java.rmi.Remote;
import java.rmi.RemoteException;
//
// This is remote interface for Customer
public interface ICustomer extends Remote{

public boolean login(String username, String password)
throws RemoteException;
}

2. 实现远程接口

实现文件是真正的业务逻辑所在。和RMI基本上没有任何关系。

要注意的是

  • 类要继承java.rmi.UnicastRemoteObject 并且实现刚才定义的接口。
  • 每个方法都要抛RemoteException
  • 要有显示的构造函数

实现文件如下: (ICustomerImpl.java)

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


public class ICustomerImpl extends UnicastRemoteObject
implements ICustomer{

public ICustomerImpl() throws RemoteException{
}
public boolean login(String username, String password )
throws RemoteException{
return true;

}
}

3. 服务器端启动程序

服务器端启动程序做两件事

  • 加载服务器端对象到JVM中
  • 将该对象注册到RMI Registry

在这个例子里面,我使用的是一般的控制台程序,据说可以用Tomcat代替,我想这个应该是可行的。毕竟,只要有个JVM能够加载对象,就能把对象注册到RMI Registry里面去。

代码如下(Server.java):

import java.rmi.Naming;

public class Server.java{
public static void main(String[] arg){
try{
ICustomerImpl cu = new ICustomerImpl();
//创建服务器端对象
Naming.rebind("cust", cu);
//注册
}catch(Exception e){
System.err.println("launcher error");
e.printStackTrace();
}
}
}

4. 编译服务器端程序

先假设所有的代码都放在d:\rmitest\下面

先到该目录下,编译所有的代码

javac Server.java

接下来,肉戏来了,需要用rmic来编译实现文件产生存根(stub),如果对这个词不是很了解,请参考一些跨进程访问的资料,一般的解决方案都是用存根/代理实现。

rmic -keep ICustomerImpl

在 运行rmic之前一定要用javac编过,rmic是找编译好的类的,不是找源程序的。rmic的工作原理是,首先反编译 ICustomerImpl.class,加入rmi架构需要的代码,然后把这个中间过程产生的Java文件编译成 ICustomerImpl_stub.class

-keep 就是让它保留中间产生的java文件。

这样基本上服务器端的事情都做完了。

客户端做这几件事情:

  1. 查找服务器端接口,要指定ip地址,端口号,接口注册名
  2. 然后可以是用接口的方法
import java.rmi.Naming;
import java.rmi.RemoteException;

public class Client{
public static void main(String[] args){
try{
ICustomer p =
(ICustomer)Naming.lookup("rmi://localhost/cust");
System.out.println(p.login("linghao","1234"));
}catch(RemoteException re){
System.out.println(re);
}catch(Exception e){
System.out.println(e);
}
}
}

客户端实际上是通过stub类来和服务器端通讯的,因此,运行的时候需要把接口文件,stub文件和客户文件放一块儿。

6. 安全策略

跨进程,跨机器访问一个不能避免的问题就是权限问题。

RMI中,是用java的访问权限管理 有两种方法来设置权限

1. 建立一个新文件test.policy,放在和server端代码一起,文件内容为

grant codeBase "file:/d:/rmitest/"
{
permission java.security.AllPermission;
};

或者在命令行中运行policytool,选"添加规则项目",在后面出来的那个对话框中,codebase填 file:/d:/rmitest/ ,然后选择"添加权限",许可中设置"All Permission".然后一路ok返回。然后选文件->另存为,取名字为test.policy放到server端程序的同一目录。

7. server端启动

首先要启动RMI注册器,这时候会出现一个空白的dos窗口,不要关掉它,否则注册服务器就没有了。

start rmiregistry

其次启动服务器端程序

java -Djava.rmi.server.codebase=file:/d:/rmitest/
-Djava.security.policy=test.policy Server

如果出现access permission exception的话,说明可能权限文件没设好,打开来看看。

注意,服务器端的两个程序都是不会返回的,每次你都要开个新窗口

8. Client端启动

注意ICustomer,ICustomerImpl_Stub.class 和 Client.class要放在一起

java Client运行后,如果一步一步照着做的话,应该能看到返回值为true;

9. 小结

本文是对RMI开发的一个极其简单,极其粗浅的介绍。很多系统的知识都没有写出来,目的就为了大家刚接触的时候上手快一些。

很多介绍也是某一种可选的方案(为了快速学习而选择的方案)罢了,专业的代码需要考虑更多的内容,比如下面列出的一些就需要考虑:

  • 服务器端程序不一定要继承java.rmi.UnicastRemoteObject, 实现更灵活
  • 端口号如果不写就是用默认的1099,但是也可以自己指定
  • 服务器端的安全设置
  • 远程调用的开销很大,是否要考虑一些模式如Gateway, DTO之类的。
  • 服务器端的宿主容器选择

更深层次的介绍还是请查看参考资料里面列的链接。

参考资料

事实上,大多数的书都很厚,如果像快速的学习RMI的用法就不要看那些书。看完了,项目也结束了。

一些有用的Link

[sun公司的RMI教程]http://java.sun.com/developer/onlineTraining/rmi/RMI.html

[sun公司的RMI培训资料]http://java.sun.com/docs/books/tutorial/rmi/running.html

没有评论: