`
jiangshuiy
  • 浏览: 335976 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

设计模式感触之代理模式-远程代理

 
阅读更多

 

1 远程代理的意义

远程代理为一个位于不同的地址空间的对象提供一个局域代表对象,这个不同的地址空间可以是在本机器中,也可以是在另一台机器中,远程代理还有个酷炫的名字:大使。

2 远程代理的结构

远程代理是代理模式的经典应用,类似客户端/服务器模式,是远程通信的一个缩影。示意图示如下:

 

3 代码示例:

我们需要对一家连锁店里的库存信息进行监控,以便准确的知道不同店的运行情况:

构建一个商店监视器,报告关于商店的位置和库存信息:

import java.rmi.RemoteException;

public class StoreMonitor {
    RemoteStore store;

    public StoreMonitor(RemoteStore store) {
        this.store = store;
    }

    public void report() throws RemoteException {
        System.out.println("Store location: " + store.reportLocation());
        System.out.println("Store count: " + store.reportCount());
    }
}

 

这里定义了一个RemoteStore,其实它是我们真实需要的一个代理:

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

public interface RemoteStore extends Remote {
    public String reportLocation() throws RemoteException;

    public int reportCount() throws RemoteException;
}

 

RemoteStore接口的一个实现,能够用来完成远程服务调用:

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

public class DefaultRemoteStore extends UnicastRemoteObject implements RemoteStore {
    private static final long serialVersionUID = -6415918724751304895L;
    private int               count;
    private String            location;

    public DefaultRemoteStore(int count, String location) throws RemoteException {
        this.count = count;
        this.location = location;
    }

    @Override
    public String reportLocation() throws RemoteException {
        return location;
    }

    @Override
    public int reportCount() throws RemoteException {
        return count;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Remote location is: ");
        sb.append(location);
        sb.append("\n");
        sb.append("Curret count is: ");
        sb.append(count);
        return sb.toString();
    }

}

 下面是服务器端绑定的代码,即服务器那边将自己的信息注册以便能提供服务:

import java.rmi.Naming;

public class StoreTestDriver {
    public static void main(String[] args) {
        DefaultRemoteStore store = null;
        int count;
        if (args.length < 2) {
            System.out.println("...");
            System.exit(1);
        }

        try {
            count = Integer.parseInt(args[1]);
            store = new DefaultRemoteStore(count, args[0]);
            Naming.rebind("//" + args[0] + "/store", store);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 真实客户端的调用代码:

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class MonitorTestDriver {

    public static void main(String[] args) throws MalformedURLException, RemoteException,
            NotBoundException {
        String[] locations = { "rmi://localhost/store" };
        StoreMonitor[] monitor = new StoreMonitor[locations.length];
        for (int i = 0; i < locations.length; i++) {
            RemoteStore reporter = (RemoteStore) Naming.lookup(locations[i]);
            monitor[i] = new StoreMonitor(reporter);
            System.out.println(monitor[i]);
        }

        for (int i = 0; i < monitor.length; i++) {
            monitor[i].report();
        }
    }
}

 

代码很简单,下面说一下运行:

首先需要编译远程的服务:

>>rmic DefaultRemoteStore

有一点需要注意的是,如果是srcbin分开存放的话,rmic是针对编译之后的class文件的,此处将产生DefaultRemoteStore _Stub.class文件。

服务注册:

>>rmiregistry

此处需要注意的是:DefaultRemoteStoreDefaultRemoteStore _Stub虽然在同一路径下,但是stub不会直接加载,而是由DefaultRemoteStore在向rmi注册时,要求rmiregistry去加载DefaultRemoteStore _Stub的,也就是说生成的stub是为rmiregistry所用的。因此在执行rmiregistry之前,需要设置classpath使的stub能被识别。最简单的方式是进入到stub所在的目录再执行rmiregistry,这里应用了classpath中的当前目录“..

服务端提供服务:

>>java StoreTestDriver localhost 100

类似的,还可以添加一些其他的。

监视:

>>java MonitorTestDriver

将能取得注册的信息。

 

RMI现在直接使用的不多,但作为J2EE几大核心技术之一,仍应用在很多框架中。

 

  • 大小: 24.2 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics