码迷,mamicode.com
首页 > 其他好文 > 详细

代理模式

时间:2016-04-07 20:55:31      阅读:281      评论:0      收藏:0      [点我收藏+]

标签:

代理模式 :为其它对象提供代理,以控制对这个对象的访问。

代理模式的特征:代理类(proxyClass)与委托类(realClass)有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类(调用realClass的方法,实现代理的功能),以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 

作用:主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话,比如可以添加调用日志,做事务控制等

 

 

1.为了更好的理解代理模式,先理解静态代理

模拟支付宝支付,大家在淘宝买过东西都知道,买家付款后,钱放在支付宝里,不会立刻给商家,待用户确认收货后,才会支付给商家,这里支付宝就相当于代理用户付款给商家。

 

支付接口

package com.proxy;

public interface Pay {
    public boolean pay();
}

 

委托类实现了支付接口

package com.proxy;

public class Customer implements Pay{
    @Override
    public boolean pay() {
        System.out.println("网上购物使用支付宝结账付款");
        return true;
    }
}

 

代理类也要实现pay接口,包含委托类对象(关联关系)

package com.proxy;

public class AliPay implements Pay{
    private Customer customer = null;
    public AliPay(Customer customer){
        this.customer = customer;
    }
    
    @Override
    public boolean pay() {
        if(customer.pay()){
            System.out.println("用户收到货物,支付包支付给商家完成");
        }
        return customer.pay();
    }
}

 

测试

package com.proxy;

public class TestProxy {
    public static void main(String[] args) {
        Customer customer = new Customer();
        AliPay aliPay = new AliPay(customer);
        if(aliPay.pay()){
            System.out.println("整个购物流程完成!");
        }else{
            System.out.println("付款失败!");
        }
    }
}

 

结果:

网上购物使用支付宝结账付款
用户收到货物,支付包支付给商家完成
整个购物流程完成!

 

使用静态代理发现,代理类只能为一个接口服务,这样会产生许多代理类。这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 

 

动态代理:

代理类

package com.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyPay implements InvocationHandler {
    private Object target;  
    
    /**
     * @param proxy  代理的实例proxy instance  
     * @param method 代理的实例proxy instance调用接口的方法
     * @param args   调用实际类方法的参数数组,没有参数为null,基本类型会转成封装类
     * @return
     * @date 2016-4-7
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object pay =  method.invoke(target, args);
        if((Boolean) pay){
            System.out.println("用户收到货物,支付包支付给商家完成");
        }
        return pay;
    }

    
    /**
     * loader : 类加载器
     * interfaces : 代理类实现的接口
     * h :调用方法
     * 
     * public static Object newProxyInstance(ClassLoader loader,
                      Class<?>[] interfaces,
                      InvocationHandler h)
     */
    public Object bind(Object target) {  
        this.target = target;  
        //取得代理对象  
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
                target.getClass().getInterfaces(), this);   
    }  

}

动态代理测试

package com.proxy;

public class TestDynamicProxy {
    public static void main(String[] args) {
        Customer customer = new Customer();
        ProxyPay proxyPay = new ProxyPay();
        Pay pay =  (Pay) proxyPay.bind(customer);
        if(pay.pay()){
            System.out.println("整个购物流程完成!");
        }else{
            System.out.println("付款失败!");
        }
    }
}

结果:

网上购物使用支付宝结账付款
用户收到货物,支付包支付给商家完成
整个购物流程完成!

 

虽然完成了动态代理的代码操作,但是对于整个流程还是有些疑惑,是怎么调用代理类中的invoke方法。

于是看源代码发现

public static Object newProxyInstance(ClassLoader loader,
                      Class<?>[] interfaces,
                      InvocationHandler h)
    throws IllegalArgumentException
    {
    if (h == null) {
        throw new NullPointerException();
    }

    /*
     * Look up or generate the designated proxy class.
     */
    Class cl = getProxyClass(loader, interfaces);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        Constructor cons = cl.getConstructor(constructorParams);
        return (Object) cons.newInstance(new Object[] { h });
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString());
    } catch (IllegalAccessException e) {
        throw new InternalError(e.toString());
    } catch (InstantiationException e) {
        throw new InternalError(e.toString());
    } catch (InvocationTargetException e) {
        throw new InternalError(e.toString());
    }
    }
/*
* Returns the <code>java.lang.Class</code> object for a proxy class
* given a class loader and an array of interfaces. The proxy class
* will be defined by the specified class loader and will implement
* all of the supplied interfaces. If a proxy class for the same
* permutation of interfaces has already been defined by the class
* loader, then the existing proxy class will be returned; otherwise,
* a proxy class for those interfaces will be generated dynamically
* and defined by the class loader.
*/
getProxyClass方法就是根据给定的classload和interface生成代理类,如果存在,就返回存在的代理类。

public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println(proxy.getClass().getName());
        Method[] methods = proxy.getClass().getMethods();
        Class[] interfaces = proxy.getClass().getInterfaces();
        for (Class interface1 : interfaces) {
            System.out.println(interface1.getName());
        }
        for (Method method1 : methods) {
            System.out.println(method1.getName());
        }
        System.out.println("-------");
        System.out.println(proxy.getClass().getMethod("pay", null));
        Object pay =  method.invoke(target, args);
        if((Boolean) pay){
            System.out.println("用户收到货物,支付包支付给商家完成");
        }
        return pay;
    }

结果:

$Proxy0
com.proxy.Pay
hashCode
equals
toString
pay
isProxyClass
newProxyInstance
getInvocationHandler
getProxyClass
wait
wait
wait
getClass
notify
notifyAll
-------
public final boolean $Proxy0.pay()
网上购物使用支付宝结账付款
用户收到货物,支付包支付给商家完成
整个购物流程完成!

 

得出结论:动态的会生成$Proxy0代理类,代理类中的pay方法调用了invoke方法。



 

代理模式

标签:

原文地址:http://www.cnblogs.com/chenxiaocai/p/5365134.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!