关于rmi的研究

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

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

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

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

Dynamic code downloading usingRMI
(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 {



    

    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'mrunner " );
}

}

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

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

多次运行客户端可以发现count在增长,也就是说对于export出的远程对象,状态是始终保存的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值