Java设计模式之代理模式

来源:互联网 发布:thinkphp5 nginx配置 编辑:程序博客网 时间:2024/06/13 07:45

代理模式

    代理模式是一种应用非常广泛的设计模式,当客户端代码需要调用某个对象时,客户端实际上不关心是否准确得到该对象,它只要一个能提供该功能的对象即可,此时我们就可返回该对象的代理(Proxy)。

代理就是一个Java对象代表另一个Java对象来采取行动。如:
静态代理模式:

public interface Image {    public void show();}
package com.mystudy.designPattern.proxy;public class BigImage implements Image {    public void show() {        System.out.println("这是BigImage");    }}
package com.mystudy.designPattern.proxy;/** * hibernate默认启用延迟加载,当系统加载A实体时,A实体关联的B实体并未被加载出来, * A实体所关联的B实体全部是代理对象——只有等到A实体真正需要访问B实体时, 系统才会去数据库里抓取B实体所对应的记录。 */public class ImageProxy implements Image {    // 组合一个image实例,作为被代理的对象    // //真实对象的引用    private Image image;    public ImageProxy(Image image) {        this.image = image;    }    /**     *重写Image接口的show()方法, 该方法用于控制对被代理对象的访问, 并根据需要负责创建和删除被代理对象     */    public void show() {        // 只有当真正需要调用image的show方法时才创建被代理对象        if (image == null) {            image = new BigImage();        }        image.show();    }}

静态代理模式测试代码:

package com.mystudy.designPattern.proxy;public class ImageProxyTest {    public static void main(String[] args) {        Image bigImage = new BigImage();        Image imageProxy = new ImageProxy(bigImage);        imageProxy.show();    }}

测试结果:这里写图片描述
代理模式的应用:

    hibernate默认启用延迟加载,当系统加载A实体时,A实体关联的B实体并未被加载出来,A实体所关联的B实体全部是代理对象——只有等到A实体真正需要访问B实体时,系统才会去数据库里抓取B实体所对应的记录。

借助于Java提供的Proxy和InvocationHandler,可以实现在运行时生成动态代理的功能,而动态代理对象就可以作为目标对象使用,而且增强了目标对象的功能。在代理对象前后就可以添加我们自己的操作。如:

package com.mystudy.designPattern.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class ImageInvokationHandler implements InvocationHandler {    private Image bigImage;    public void setTarget(Image bigImage) {        this.bigImage = bigImage;    }    /**     * 动态代理类$Proxy0调用xiangQin方法时会调用它自己的xiangQin方法,     * 而它自己的xiangQin方法里面调用的是super.h.invoke(this, , ),也就是父类Proxy的h的invoke方法,     * 也就是ReadyInvocationHandler类的invoke方法。 所以,invoke(Object proxy, Method m,     * Object[] args)种的proxy实际上就是动态代理类$Proxy0,     * 如果你将其强转成XiangQinInterface然后调用它的xiangQin方法,然后它就会调用super.h.invoke(this, ,     * ),这样就会死循环。     */    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        TxUtil txUtil = new TxUtil();        txUtil.beginTx();        Object result = method.invoke(bigImage, args);        txUtil.endTx();        return result;    }}

在代理对象前后就可以添加我们自己的操作:

package com.mystudy.designPattern.proxy;public class TxUtil {    public void beginTx() {        System.out.println("===模拟业事务开始");    }    public void endTx() {        System.out.println("===模拟事务结束");    }}

测试代码:

package com.mystudy.designPattern.proxy;import java.lang.reflect.Proxy;public class ImageInvokationHandlerTest {    public static void main(String[] args) {        // 先将BigImage实现类实例化,也就是得到Image接口的一个实例对象        Image bigImage = new BigImage();        /**         * 得到BigImage这个类的一个代理类,同时为代理类绑定了一个处理类ImageInvokationHandler。         * 听着很绕口,其实就是每次调用bigImage这个子类的show()方法时, 不是Image这个BigImage类的实例去调用,         * 而是这个bigImage的代理类ImageInvokationHandler去调用它自己的invoke方法,         * 这个invoke方法里呢可以调用bigImage这个实例的show()方法         */        /**         * 在java种怎样实现动态代理呢 第一步,我们要有一个接口,还要有一个接口的实现类,而这个实现类呢就是我们要代理的对象,         * 所谓代理呢也就是在调用实现类的方法时,可以在方法执行前后做额外的工作,这个就是代理。         * 第二步,我们要自己写一个在要代理类的方法执行时,能够做额外工作的类,而这个类必须继承InvocationHandler接口,         * 为什么要继承它呢?因为代理类的实例在调用实现类的方法的时候,不会调真正的实现类的这个方法,         * 而是转而调用这个类的invoke方法(继承时必须实现的方法),在这个方法中你可以调用真正的实现类的这个方法。         * 第三步,在要用代理类的实例去调用实现类的方法的时候,写出下面两段代码。         */        ImageInvokationHandler handler = new ImageInvokationHandler();        handler.setTarget(bigImage);        Image image = (Image) Proxy                .newProxyInstance(bigImage.getClass().getClassLoader(),                        bigImage.getClass().getInterfaces(), handler);        image.show();        /**         * 这里要解释下中部那段长长的代码的意思,以及具体做了哪些工作?         * 第一,根据bigImage.getClass().getClassLoader()这个要代理类的类加载器和         * bigImage.getClass().getInterfaces()要代理类所实现的所有的接口         * 作为参数调用Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces)         * 的方法返回代理类的java.lang.Class对象,也就是得到了java动态生成的代理类$Proxy0的Class对象。         * 同时,java还让这个动态生成的$Proxy0类实现了要代理类的实现的所有接口,并继承了Proxy接口。         * 第二,实例化这个动态生成的$Proxy0类的一个实例,实例化代理类的构造函数为Proxy(InvocationHandler h),         * 也就是说要实例化这个动态生成的$Proxy0类,必须给它一个InvocationHandler参数,也就是我们自己实现的用来在代理类         * 方法执行前后做额外工作的类ReadyInvocationHandler。         * 这段代码Proxy.newProxyInstance(bigImage         * .getClass().getClassLoader(),bigImage         * .getClass().getInterfaces(),handler) 得到的其实是一个类名叫$Proxy0 extends Proxy         * implements Image的类。 第三,将这个$Proxy0类强制转型成Image类型,调用show()方法。         */    }}
    在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java的动态代理机制。

另外一片关于代理模式的介绍也很详细,可作参考:http://www.cnblogs.com/xiaoluo501395377/p/3383130.html

原创粉丝点击