概述

代理模式为一个对象提供一个替身以控制对这个对象的访问。其实就是代理就是做到类似转发的功能,针对不同代理,转发的具体实现不同。从原理知道他就是控制客户对一个对象的访问,它跟现实中的中介代理类似,只是作为代表做一些受理工作,真正执行的并不是它自己。

结构图

clipboard.png
解析:被代理类 和 代理类实现同一个接口,通过代理类的对象来访问被代理的对象。

应用实例

在这个例子中,主要讲解远程代理,它可以作为另一个JVM上的本地代表。客户端调用代理的方法,代理会利用网络把请求转发到远程执行,并把执行结果通过网络返回到代理,最终返回到客户端。

  下面使用引用java RMI(Remote Method Invoke远程方法调用)的例子讲解远程代理模式。它的的工作原理图如下,用户向服务器A发起话费充值请求,服务器A通过网络调用服务器B的方法,服务器B把充值结果返回到服务器A,最后返回到用户。
clipboard.png

代码实现如下,首先创建一个远程接口

package com.jet.pattern.proxy;

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

/**
 * description:
 * 远程接口,其继承java的Remote接口,真正干活对象和代理都要实现这个接口
 * Created by Administrator on 2017/1/17.
 */
public interface MyRemote extends Remote{
    // 远程调用有风险告诉客户端
    public String request(int money) throws RemoteException, MalformedURLException, NotBoundException;
}

创建远程对象

package com.jet.pattern.proxy.impl;

import com.jet.pattern.proxy.MyRemote;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;

/**
 * description:
 * 真正干活的对象,接受代理对象的访问
 * Created by Administrator on 2017/1/17.
 */
// 继承UnicastRemoteObject,让jvm帮我们完成远程调用
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{
    // 父类构造器抛出了异常,所以子类构造器也需要抛出异常
    public MyRemoteImpl() throws RemoteException {
    }

    @Override
    public String request(int money) throws RemoteException {
        System.out.println("充值" + money + "元话费成功");
        return "充值成功";
    }

    public static void main(String[] args) {
        try {
            // 产生远程对象
            MyRemote service = new MyRemoteImpl();

            // 注册远程访问接口
            LocateRegistry.createRegistry(8888);

            // 注册远程对象,注册名为RemoteHello,代理访问时指定这个名称就可以找到本类,
            Naming.rebind("rmi://localhost:8888/RemoteHello",service);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

创建代理对象

package com.jet.pattern.proxy.impl;

import com.jet.pattern.proxy.MyRemote;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

/**
 * description:
 * 代理对象,控制客户端的访问,把客户端访问请求转发到真正干活的对象
 * Created by chenzanjin on 2017/2/4.
 */
public class Proxy implements MyRemote {
    @Override
    public String request(int money) throws RemoteException, MalformedURLException, NotBoundException {
        MyRemote remote = (MyRemote)Naming.lookup("rmi://localhost:8888/RemoteHello");
        return remote.request(money);
    }
}

创建访问客户端

package com.jet.pattern.proxy.test;

import com.jet.pattern.proxy.MyRemote;
import com.jet.pattern.proxy.impl.Proxy;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

/**
 * description:
 * 代理客户端,测试对代理的访问
 * Created by chenzanjin on 2017/2/4.
 */
public class ProxyClient {
    public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException {
        MyRemote proxy = new Proxy();
        System.out.println(proxy.request(100));
    }
}

测试步骤:

  1、启动MyRemoteImpl 类的main方法,绑定远程对象到jvm。

  2、启动ProxyClient 类的main方法,对代理对象发起访问。

代码输出如下:

  MyRemoteImpl 类会输出:充值100元话费成功

  ProxyClient 类输出:充值成功

其他代理

1、虚拟代理:可以作为创建开销大的对象的代表,虚拟代理让我们真正需要使用一个对象时才会去创建这个对象。在对象创建前和创建中,虚拟代理扮演真实对象的替身,当对象创建完毕后,虚拟代理会把请求直接委托给真实对象。虚拟代理在手机页面加载中经常可以见到,比如打开页面显示"**正在玩命加载中..."。

  2、缓存代理:可以理解成把网络上的静态资源或者不常改变的数据保存在本地,再次访问的这次数据的时候直接从本地读取。应用例子有页面的缓存机制、cdn、app缓存机制等。

  3、保护代理:根据角色或者其他机制控制用户对一些资源的访问权限。这常见于一些网站需要登录才能获取更多的内容,struts2和spring的拦截器等。

  4、静态代理:可以理解为对象由代理创建,在创建前后做一些事情,比如统计创建了多少对象,但静态代理只能创建一个或固定的几个对象。详见:http://blog.csdn.net/lidatgb/...

  5、动态代理:其用途跟静态代理类型,但可以利用反射机制动态地创建对象,可以减少代理代码的重复,有更好的扩展性。详见:http://blog.csdn.net/lidatgb/...

  6、正向代理:用户可以指定代理服务器转发请求到目标服务器完成,用户知道代理服务器地址和目标服务器地址。常见于FQ代理服务器。

  7、反向代理: 用户访问的目标服务器其实是代理服务器,代理服务器做负载均衡后把请求转发到真正的目标服务器执行。常见于负载均衡服务器。

使用场景

由代理的概述中知道,但需要控制对资源或者对象的访问时使用代理模式。从代理的种类中可以进一步看清代理模式的使用场景,无非就是转发远程请求、作为创建开销大对象的替身、在本地保存网络资源、控制一些受保护资源的权限访问、作负载均衡。


Huangy远
530 声望63 粉丝