RMI的有点如下:
1:面向对象,RMI可以将完整的对象作为参数传递或者返回,而不仅仅是基本的数据类型。
2: 安全,RMI使用java内置的安全管理机制,保证下载程序的安全性。
3:简单而且易于编写,和socket机制相比,RMI屏蔽了底层的实现细节,编写程序时无需考虑传输协议。同时RMI可以使用http进行通信,从而可以跨过防火墙和代理服务器进行远程通信。
4:跨平台。RMI是java的一部分,具有“编写一次,到处运行”的优点。
5:并行计算,RMI采用多线程处理方法,服务器利用java线程并行处理客户端的请求。
Client Server
Stubs | Skelton |
Remote reference Layer |
Transport |
在RMI中,调用远程对象的对象被称为客户机对象(Client Object)而远程对象被称为服务器对象(Server Object),同时引入了两种特殊类型对象,存根(stub)和框架(Skelton).存根是代表远程对象的客户端对象,它和远程对象具有相同的接口或方法列表,当客户端调用远程对象时,实际上是由相应的存根对象代理完成,存根通过对象处理远方所有细节,存根通过RMI基础结构将请求转发到远程对象,最后有远程对象执行请求。在服务器端,框架对象处理“远方”的所有细节,因此实际的远程对象不必担心这些细节。也就是说,完全可以像编写本地对象一样来编写远程对象。框架将远程对象从RMI基础结构分离开来。
到此,我们应该对RMI的基本工作原理有个初步的了解,那么现在让我们开始编写一个实际的RMI应用程序吧!RMI应用程序的编写分为一下几步!
第一步:编写远端接口。
要产生远端接口,必须依循以下规则:
1。远端接口必须被声明为public,否则客户端在试着装在“实现出远端接口”的远端对象时会收到错误消息。
2。远端对象必须继承java.rmi.Remote这一接口。
3。每个远端接口中的函数,除了自定义异常外,还必须抛出java.rmi.RemoteException.
4.作为引数或返回值的远端对象,都必须被声明为远端接口,而非实际class.
现在让我们开始编写一个取得系统时间的远端接口。如下:
package net.xiaobo.remoteserver;
import java.util.*;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface HelloRemote extends Remote{
public Date getTime() throws RemoteException;
}
以上接口均符合以上规定。
第二步:实现出远端接口。
服务器必须内含一个继承自UnicastRemoteObject并实现出远端接口的class,这个class也可以拥有额外的函数,但只有在远端接口中定义的函数才可为客户端调用。如下:
package net.xiaobo.remoteserver;
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.util.*;
public class HelloRemoteImp extends UnicastRemoteObject implements HelloRemote{
public Date getTime()throws RemoteException{
return new Date();
}
public HelloRemoteImp()throws RemoteException{
}
public static void main(String args[])throws Exception{
System.setSecurityManager(new RMISecurityManager());
HelloRemoteImp hri=new HelloRemoteImp();
Naming.bind("/HelloRemoteImp",hri);
System.out.println("Succeed in binding,now ready to do time");
}
}
第三步:(可由可无,我自己的习惯,大家也可以在%java_home/jre/lib/security/java.policy中配置)
编写权限文件,与上述文件在同一个目录下。名位policy.
/*
* Only grant permissions to the local class path (the current directory).
*/
grant codeBase "file:." {
permission java.net.SocketPermission "*:1024-", "connect,accept";
};
第四步:运行以上文件,命令如下:
javac -d . HelloRemote.java 该命令产生目录为net/xiaobo/remoteserver/HelloRemote.class
javac -d . HelloRemoteImp.java 该命令产生目录为net/xiaobo/remoteserver/HelloRemoteImp.class
rmic -d . HelloRemoteImp 该命令产生目录为net/xiaobo/remoteserver/HelloRemoteImp_Stub.class
net/xiaobo/remoteserver/HelloRemoteImp_Skelton.class
第五步:启动服务器并设定注册薄进行绑定。命令如下:
rmiregistry (启动注册薄服务器)
java -Djava.security.policy=policy net.xiaobo.remoteserver.HelloRemoteImp
该命令-Djava.security.policy=policy指定java解释程序用指定的policy文件设定权限,同时启动服务器,进行远端对象的绑定。即执行
Naming.bind("/HelloRemoteImp",hri);
该代码会将服务名称HelloRemoteImp和对象hri进行绑定。便于在客户端查询远端对象。如果运行成功,则会出现一下提示:Succeed in binding,now ready to do time
第六步:编写客户端代码进行测试。
代码如下:
package net.xiaobo.remoteclient;
import net.xiaobo.remoteserver.*;
import java.rmi.*;
import java.rmi.registry.*;
public class DisplayTime{
public static void main(String[] args)throws Exception{
if(System.getSecurityManager() == null){
System.setSecurityManager(new RMISecurityManager());
}
HelloRemote t=(HelloRemote)Naming.lookup("/HelloRemoteImp");
System.out.println(t.getTime());
}
}
该代码中运用Naming.lookup("/HelloRemoteImp")来取得一个远程对象的引用,此时我们可以将t看做是本地对象一样,来操作它的方法。
现在在命令行下执行一下命令:
javac -d . DisplayTime.java
在执行如下命令时请确保第五步运行正常,并且服务器已经启动(该命令行窗口没有反应,这是我的状况!)
java -Djava.security.policy=policy net.xiaobo.remoteclient.DisplayTime
如果运行正常就会出项一下结果:
Mon Feb 21 19:16:32 CST 2005
至此,我对rmi的初步学习也一个成功的例子告终,以上均是我的实际操作,其中在所难免有很多不足,我相信在今后的学习中自己会有更多的了解。