Java代理模式

什么是代理模式:

代理模式是23种设计模式中的一种,其思想是:为目标对象提供代理,外部想要访问目标对象就必须通过代理,这样做的意义在于隔离目标对象,比如 明星跟经纪人,就是很典型的代理模式,明星就是目标,经纪人就是代理,现在有一家公司想要找明星拍广告,怎么办,能直接找这个明星吗,不能,那就去找他的代理(经纪人)吧,具体经纪人如何跟明星商量的,广告公司不用管。画个图:


代理模式.png

三种代理模式:

1. 静态代理:
首先我们定义一个目标对象和代理对象的公共接口(保证在使用者看来,貌似我就是调用了目标对象的方法)

public interface IStart {
    void advertising();
}

接下来,我们定义一个目标类

public class Star implements IStart {
    String name;

    public Star(String name) {
        super();
        this.name = name;
    }

    // 拍广告
    @Override
    public void advertising() {
        System.out.println("我是" + name + ",我给你拍霸王洗发水的广告");
    }
}

代理类:

public class StarProxy implements IStart {
    //我是代理类,我在创建的时候就要给我指定,我要代理谁
    private Star star;
    public StarProxy(Star star) {
        super();
        this.star = star;
    }

    @Override
    public void advertising() {
        star.advertising();
    }
}

好了,所有类都定义好了,我们开始使用

public static void main(String[] args) {
        Star star = new Star("成龙");
        StarProxy proxy = new StarProxy(star);
        //拍广告
        proxy.advertising();
    }

输出结果:我是成龙,我给你拍霸王洗发水广告,是不是很简单呢,对于使用者来说,我调用的是代理对象的方法,但是真正做事的还是目标对象
大家有没有发现,我的代理类和目标类都实现了同一个接口,IStar,那么如果我现在有新的功能来了,比如,我不仅拍广告,我还可以拍电影,我还可以唱歌,如果添加,那么目标类和代理类都需要维护,这就麻烦了,没关系,下面我们看看动态代理


2. 动态代理
动态代理的代理对象不需要实现接口,动态代理的核心类:java.lang.reflect.Proxy,代理对象的生成一般通过
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法来生成的,需要三个参数:

  1. ClassLoader 目标对象的类加载器
  2. interfaces[] 目标对象所实现的所有接口,可以是一个也可以是多个
  3. InvocationHandler 事件处理的方法(android中的handler有点像,反正只要知道,他是处理事件的,下文会有代码)
    我们直接上代码,Star和IStar都不用换,创建StarProxy2
public class StarProxy2 {
    Star star;

    public StarProxy2(Star star) {
        super();
        this.star = star;
    }
    public Object getProxy(){
        return Proxy.newProxyInstance(star.getClass().getClassLoader(), star.getClass().getInterfaces(), new InvocationHandler() {
            
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                //下面代码invoke(),是不是很熟悉,没错,就是反射
                Object returnObj = method.invoke(star, args);
                return returnObj;
            }
        });
        
    }
}

public static void main(String[] args) {
        Star star = new Star("成龙");
        StarProxy2 proxy2 = new StarProxy2(star);
        IStart iStart = (IStart) proxy2.getProxy();
        iStart.advertising();
    }

动态代理和静态代理的区别是,动态代理中,代理类不用实现接口,共同点是目标类需要实现接口,那么有没有目标类和代理类都不用实现接口的代理方式呢,有!哈哈,这就是我们接下来要说的,Cglib代理


3. Cglib代理(这里仅介绍用法)先去github下载Cglib,他还要依赖asm和ant所以都要分别下载

Cglib又叫子类代理,为什么呢,其原理就是在内存中创建目标对象的子类作为代理类。他的用途很广泛,例如 Spring AOP。

//新建一个类,我这里叫StarProxy3,实现MethodInterceptor,这个接口就是来处理代理的方法
public class StarProxy3 implements MethodInterceptor{
    Star star;

    public StarProxy3(Star star) {
        super();
        this.star = star;
    }
    public Object getProxy(){
        //这是一个工具,我们告诉他目标对象的Class,因为一会他要给他创建一个子类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(star.getClass());
        //这里是设置回掉接口,就是我们实现MethodInterceptor的方法intercept;
        enhancer.setCallback(this);
        //开始创建代理类了
        return enhancer.create();
        
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {
         //通过反射调用,和动态代理一样
        Object returnObj = method.invoke(star, args);
        return returnObj;
    }
}


public static void main(String[] args) {
        Star star = new Star("成龙");
        //这里的proStar实际是Star类的子类
        Star proStar = (Star) new StarProxy3(star).getProxy();
        proStar.advertising();
        
        
    }

注:这里有一个小细节,被代理的类一定要保证有空参构造,因为Cglib代理就是通过目标类的空参构造来创造其子类,并为其代理,若没有,则会报错

总结:三种代理方式,一般第二种就完全搞定了,想研究Cglib源码的童鞋可以点这里

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • 设计模式文章陆续更新 java单例模式java工厂模式java状态模式 这几天在看一些框架源码时看到了一个很奇妙的...
    林锐波阅读 986评论 0 10
  • 版权声明:本文为博主原创文章,未经博主允许不得转载 前言 Java 代理模式在 Android 中有很多的应用。比...
    cc荣宣阅读 813评论 0 7
  • 代理实现可以分为静态代理和动态代理。静态代理:静态代理模式其实很常见,比如买火车票这件小事:黄牛相当于是火车站的代...
    国祥同学阅读 254评论 0 1
  • 偶尔会反思一个问题,年少时拜师学国画时,师傅有位得意门生,现在京有私人工作室,房,车等,已是实力派花鸟画家,润格高...
    9fc37d54b552阅读 193评论 0 0
  • 你我埋入一颗种子 陪着它发芽 陪着它开花 嬉笑着在它周围旋转 可转着转着我就跟丢了你…… 寻啊,寻了多年,又回到这...
    米蓝色的天空阅读 285评论 2 5