回家作业上要用到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文件。
这样基本上服务器端的事情都做完了。
客户端做这几件事情:
- 查找服务器端接口,要指定ip地址,端口号,接口注册名
- 然后可以是用接口的方法
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