静态代理和动态代理

静态代理

我们平常去电影院看电影的时候,在电影开始的阶段是不是经常会放广告呢?

电影是电影公司委托给影院进行播放的,但是影院可以在播放电影的时候,产生一些自己的经济收益,比如卖爆米花、可乐等,然后在影片开始结束时播放一些广告。

现在用代码来进行模拟。

首先得有一个接口,通用的接口是代理模式实现的基础。这个接口我们命名为 Movie,代表电影播放的能力。

package com.frank.test;

public interface Movie {

    void play();

}

然后,我们要有一个真正的实现这个 Movie 接口的类,和一个只是实现接口的代理类。

public class RealMovie implements Movie {

    @Override

    public void play() {

        System.out.println("您正在观看电影 《肖申克的救赎》");

    }

}

这个表示真正的影片。它实现了 Movie 接口,play() 方法调用时,影片就开始播放。那么 Proxy 代理呢?

public class Cinema implements Movie {

    RealMovie movie;

    public Cinema(RealMovie movie) {

        super();

        this.movie = movie;

    }

    @Override

    public void play() {

        guanggao(true);

        movie.play();

        guanggao(false);

    }

    public void guanggao(boolean isStart){

        if ( isStart ) {

            System.out.println("电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!");

        } else {

            System.out.println("电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!");

        }

    }

}

Cinema 就是 Proxy 代理对象,它有一个 play() 方法。不过调用 play() 方法时,它进行了一些相关利益的处理,那就是广告。现在,我们编写测试代码。

public class ProxyTest {

    public static void main(String[] args) {

        RealMovie realmovie = new RealMovie();

        Movie movie = new Cinema(realmovie);

        movie.play();

    }

}

然后观察结果:

电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!

您正在观看电影 《肖申克的救赎》

电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!

现在可以看到,代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

上面介绍的是静态代理的内容,为什么叫做静态呢?因为它的类型是事先预定好的,比如上面代码中的 Cinema 这个类。下面要介绍的内容就是动态代理。

动态代理

既然是代理,那么它与静态代理的功能与目的是没有区别的,唯一有区别的就是动态与静态的差别。

那么在动态代理的中这个动态体现在什么地方?

上一节代码中 Cinema 类是代理,我们需要手动编写代码让 Cinema 实现 Movie 接口,而在动态代理中,我们可以让程序在运行的时候自动在内存中创建一个实现 Movie 接口的代理,而不需要去定义 Cinema 这个类。这就是它被称为动态的原因。

也许概念比较抽象。现在实例说明一下情况。

假设有一个大商场,商场有很多的柜台,有一个柜台卖茅台酒。我们进行代码的模拟。

public interface SellWine {

    void mainJiu();

}

SellWine 是一个接口,你可以理解它为卖酒的许可证。

public class MaotaiJiu implements SellWine {

    @Override

    public void mainJiu() {

        System.out.println("我卖得是茅台酒。");

    }

}

然后创建一个类 MaotaiJiu,对的,就是茅台酒的意思。

我们还需要一个柜台来卖酒:

InvocationHandler :  Proxy.newProxyInstance生成动态代理类时会传入 InvocationHandler 对象,之后代理类调用方法后会自动调用这个invoke方法利用反射( method.invoke(pingpai, args)),从而在调用方法前后增加其他的代码。

注意在 GuitaiA的构造方法要传入一个对象(类型为Object,因为 Proxy.newProxyInstance 可以根据前两个参数生成不同类型的代理类()),这个对象在invoke时传入说明是哪个对象调用的这个方法。

public class GuitaiA implements InvocationHandler {

private Object pingpai;

public GuitaiA(Object pingpai) {

    this.pingpai = pingpai;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

        System.out.println("销售开始  柜台是: "+this.getClass().getSimpleName());

        method.invoke(pingpai, args);

        System.out.println("销售结束");

        return null;

    }

}

GuitaiA 实现了 InvocationHandler 这个类,这个类是什么意思呢?大家不要慌张,待会我会解释。

然后,我们就可以卖酒了。

public class Test {

        public static void main(String[] args) {

            MaotaiJiu maotaijiu = new MaotaiJiu();

            // GuitaiA ()中可以传入其他类型,此时要保证 Proxy.newProxyInstance 时传的参数类型对应。所以可以生成很多类型的代理类,调用这些类的不同方法,但是因为使用的是同一个处理类( InvocationHandler ),所以调用方法的前后逻辑都是该处理类( InvocationHandler )中的invoke方法。

            InvocationHandler jingxiao1 = new GuitaiA(maotaijiu);

            SellWine dynamicProxy = (SellWine)                     Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),

            MaotaiJiu.class.getInterfaces(), jingxiao1);

            dynamicProxy.mainJiu();

        }

}

这里,我们又接触到了一个新的概念,没有关系,先别管,先看结果。

销售开始  柜台是: GuitaiA

我卖得是茅台酒。

销售结束


看到没有,我并没有像静态代理那样为 SellWine 接口实现一个代理类,但最终它仍然实现了相同的功能,这其中的差别,就是之前讨论的动态代理所谓“动态”的原因。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1、代理概念 为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用...
    孔垂云阅读 12,303评论 4 54
  • 一、代理概念 为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用...
    wyatt_plus阅读 4,145评论 0 5
  • 代理模式是软件开发中常见的设计模式,它的目的是让调用者不用持有具体操作者的引用,而是通过代理者去对具体操作者执行具...
    Java耕耘者阅读 2,372评论 0 0
  • 千年妖道终生怪,万载修仙转世来。 一念之差行渐远,是非成败几人猜。 作者王永豪(注:新韵) 与老怪哥哥共勉~哈哈哈……
    王永豪阅读 3,089评论 8 6
  • 她从小觉得自己与众不同,冥冥中觉得自己的命运已经安排好了:她注定不是一个平凡的人,她会成为一个大人物。至于是怎样的...
    流苏小书女阅读 1,651评论 0 2