longshu

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

Proxy 代理模式

  • 代理模式:
    给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。
    在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。
    代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。

  • 代理模式分为静态代理、动态代理。
    静态代理是由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
    动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。

  • 示例类图:
    DynamicProxy_uml.png
    DynamicProxy_uml.png

  • 示例代码:

// Target
public interface Sender {
    public void send(String msg);
}
// 具体的Target
public class MailSender implements Sender {
    @Override
    public void send(String msg) {
        System.out.println("MailSender send : " + msg);
    }
}

// 聚合的形式实现静态代理
public class SenderStaticProxy implements Sender {
    private Sender target;

    public SenderStaticProxy(Sender target) {
        this.target = target;
    }

    @Override
    public void send(String msg) {
        System.out.println("发送中...");
        target.send(msg);
        System.out.println("发送完成...");
    }
}

// JDK通过实现某些结构动态产生类和对象
public class SenderDynamicProxy implements InvocationHandler {
    private Sender target;

    public SenderDynamicProxy(Sender target) {
        this.target = target;
    }

    public Sender getProxy() {
        // 动态创建一个实现了target实现了的接口(Sender)的对象
        return (Sender) Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),
                this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("method:" + method);
        System.out.println("args:" + Arrays.toString(args));

        long start = System.currentTimeMillis();
        Object result = method.invoke(target, args);
        long end = System.currentTimeMillis();
        System.out.println("运行时长=" + (end - start));
        return result;
    }
}

// cglib通过继承的方式动态代理
public class SenderCglibProxy implements MethodInterceptor {

    @SuppressWarnings("unchecked")
    public static <T> T getProxy(Object target) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new SenderCglibProxy());
        return (T) enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("method:" + method);
        System.out.println("args:" + Arrays.toString(args));

        long start = System.currentTimeMillis();
        Object result = proxy.invokeSuper(obj, args);
        long end = System.currentTimeMillis();
        System.out.println("运行时长=" + (end - start));
        return result;
    }
}

// 测试
public class ProxyTest {

    public static void main(String[] args) {
        Sender target = new MailSender();

        staticProxy(target);
        dynamicProxy(target);
        cglibProxy(target);
    }

    // 静态代理测试
    static void staticProxy(Sender target) {
        Sender staticProxy = new SenderStaticProxy(target);

        staticProxy.send("SenderStaticProxy...");
    }

    // JDK动态代理
    static void dynamicProxy(Sender target) {
        Sender dynamicProxy = new SenderDynamicProxy(target).getProxy();
        System.out.println("dynamicProxy:" + dynamicProxy.getClass());
        dynamicProxy.send("SenderDynamicProxy...");
    }

    static void cglibProxy(Sender target) {
        Sender cglibProxy = SenderCglibProxy.getProxy(target);
        System.out.println("cglibProxy:" + cglibProxy.getClass());
        cglibProxy.send("SenderCglibProxy...");
    }
}
  • 代理模式的应用场景:

如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:
1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。
2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。
使用代理模式,可以将功能划分的更加清晰,有助于后期维护。

posted on 2016-12-28 17:39  longshu  阅读(133)  评论(0编辑  收藏  举报