随笔-11  评论-10  文章-8  trackbacks-0
rmi有两个主要问题:
1. 调用如何从客户端传输到服务器端
   这个问题的是通过stub来解决的,stub负责和服务器通信,将调用传输到服务器并接收
   返回值
2. 由于stub类可以通过工具生成,但初始化必须在服务器端完成,所有如何将一个可用的
   stub传输到客户端就是我们最关心的问题

注:在1.4中stub类是必须的,在5.0中使用UnicastRemoteObject类可以不需要stub类
而由动态生成的Proxy类(实现远程接口,InvocationHandler是
RemoteObjectInvocationHandler)代替,具体见5.0的文档。如果不使用
UnicastRemoteObject类,则stub类在服务器端是必须的

rmi的核心问题是如何将一个可用的stub传输到客户端,大致有两种方法:
1. 最直观的方法,服务器和客户端直接建立连接,用任何可用的协议传输stub,缺点显而
   易见,客户端必须明确的知道服务器的地址及相关信息
2. 使用注册中心,如:rmiregistry和JNDI。这里主要讨论使用rmiregistry的情况

有一点需要注意,这里传输的只是stub的实例,而不是stub类的定义。所有stub类文件必须
在客户端和服务器端的classpath中,否则会抛出ClassNotFoundException。这样要求客户
端确实有些过分,我们希望客户端只要远程接口的定义就够了,这实际上很容易办到,下面
我们就来讨论这个问题

Dynamic code downloading using RMI
(http://java.sun.com/j2se/1.4.2/docs/guide/rmi/codebase.html)

要下载类必须设置RMISecurityManager,默认是禁止下载的

客户端可以通过网络自动下载stub,此时stub不需要在客户端的classpath中,只需要远程
接口即可。

由rmiregistry作为注册中心的远程调用

在服务器绑定远程对象到rmiregistry时,rmiregistry必须能够找到该对象的stub,它在三
个地方寻找:
1. 启动它时的CLASSPATH环境变量

2. 启动它时所在的文件夹作为classpath寻找

3. 该stub中的codebase,这个值由服务器通过系统属性 java.rmi.server.codebase 设置

若找不到则无法绑定

客户端通过rmiregistry lookup到stub对象,虚拟机从两个位置寻找stub类的定义:
1. classpath中寻找

2. stub中的codebase,这个值由rmi服务器通过系统属性 java.rmi.server.codebase 设置

由以上分析可见,服务器端只要正确设置了codebase,无论何种情况,远程调用都能顺利完成

不仅客户端可以从服务器下载类,服务器也可以从客户端下载类,只需要在客户端设置
codebase,安装RMISecurityManager即可

若服务器允许下载类,则客户端有可能在服务器上运行任何他希望的代码,如以下代码:
// 远程接口定义
package
rmi.server;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Service extends Remote {
public void hello() throws RemoteException;

public void runThread(Runnable thread) throws RemoteException;
}

// 远程接口实现,main方法作为服务器
package
rmi.server;

import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.server.RemoteStub;
import java.rmi.server.UnicastRemoteObject;
import java.security.Permission;

public class ServiceImpl implements Service {

private RemoteStub stub;

private int count;

public ServiceImpl() throws RemoteException {
stub
= UnicastRemoteObject.exportObject(this);
count
= 0;
}

public void hello() throws RemoteException {
System.out.println(
"Hello World: count = " + (++count));
}

public void runThread(Runnable thread) throws RemoteException {
Thread t
= new Thread(thread);
t.start();
}

public RemoteStub getStub() {
return stub;
}

public static void main(String[] args) {
System.setProperty(
"java.rmi.server.ignoreStubClasses", "true");
System.setProperty(
"java.rmi.server.codebase",
"file:///E:\\\\bahamut\\\\JavaWorkspace\\\\rmiserver\\\\classes\\\\");
if (System.getSecurityManager() == null) {
System.setSecurityManager(
new RMISecurityManager() {
public void checkPermission(Permission p) {
}
});
}
try {
ServiceImpl service
= new ServiceImpl();
Naming.rebind(
"service", service);
System.out.println(
"Server ready");
}
catch (Exception e) {
e.printStackTrace();
}
}

}

// 客户端
package
rmi.client;

import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.security.Permission;

import rmi.server.Service;

public class ServiceClient {

/**
*
@param args
*/
public static void main(String[] args) {
System.setProperty(
"java.rmi.server.codebase",
"file:///E:\\\\bahamut\\\\JavaWorkspace\\\\rmiclient\\\\classes\\\\");
if (System.getSecurityManager() == null) {
System.setSecurityManager(
new RMISecurityManager() {
public void checkPermission(Permission p) {
}
});
}
try {
Service service
= (Service) Naming.lookup("service");
service.hello();
Runnable runner
= new Runner();
service.runThread(runner);
}
catch (Exception e) {
e.printStackTrace();
}
}

}
package rmi.client;

import java.io.Serializable;

public class Runner implements Runnable, Serializable {

public void run() {
System.out.println(
"i'm runner");
}

}

服务器端生成stub并放在classpath中,codebase设置为能找到stub的路径,运行rmiregistry,
运行服务器。

客户端只需要Service类在classpath中,设置codebase为能找到Runner的路径,运行客户端。
客户端会从服务器下载stub,服务器会从客户端下载Runner。Runner可以执行任何操作甚至破坏
服务器上的数据。

多次运行客户端可以发现count在增长,也就是说对于export出的远程对象,状态是始终保存的
posted on 2005-11-11 19:49 JBahamut 阅读(1536) 评论(1)  编辑  收藏

评论:
# re: 关于rmi的研究 2009-03-31 16:14 | 夏登成
谢谢你,让我明白了远程方法调用!  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: