小白学Java动态代理Proxy

     动态代理是Java设计模式中使用频率较高的模式了,比如AOP将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码---解耦。刚开始接触动态代理是在设计模式和别人的博客中看到的,稍有理解就在博客中记录了下来,现在在来看,感觉就跟没学一样哈哈哈,最近看Java核心技术卷1,其在6.5小节提了一下动态代理,开头就说这是一种高级技术,是针对系统设计人员来说的(架构师),一般程序员遇到的情况少,而我感觉,不对啊,我们公司项目就用到了呀,赶紧再学习下!

首先说说概念:

什么是代理?从现实上来说,就好像我要做某件事,但是表面我上不想让别人知道实际上是我干的,我要找一个中间人来替我进行对外交互,比如我想写了情书要送给喜欢的女孩子,自己不好意思送就找一傻点儿的哥们替我送,他就是那种傻子,这种就是我们小时候认识的笨笨的,只会跑跑腿的哥们哈哈哈,吧这哥们就是我的代理,实际上写情书的是我,人家女孩子一看也喜欢我要给我回信(啧啧,一般都是这样),哥们跟小姐姐说:我拿回去读一下啊,这实际上也是拿回去给我读(他没法读,他是文盲)。所以说代理对外执行了操作,实际上是大哥我在背地里干的,有人要说了,自己送情书不是更有诚意?更能打动女神吗?让别人帮你做不是浪费人力物力还事倍功半?但是我作为一个大哥我写情书多累啊,绞尽脑汁地写一天写了500个字,自己害羞不是重点,重点是我每次写完就很累,然后想躺在床上吃零食,又懒得去买,另外每次写情书就没空写作业啦,让小弟过来帮着抄一下,我专心写情书,写完情书多累啊,可以让他在送完回来的路上再给买点儿零食啊,跑个腿啥的,而让小弟每次送情书干的这些是我是可以自己定义的,我让他干嘛就干嘛,哈哈哈!

下面先说说静态代理概念,

静态代理:代理类是在编译时就实现好的。也就是说 Java 编译完成后代理类是一个实际的 class 文件。拿泡妞来举例,首先我们定义一个借口:

/**

* 泡妞(引文垃圾,见谅)行为接口

*/

public interface FindLove {

//写情书

    void writeLovePaper();

    //送花儿

    void sendFlowers();

    //送礼物

    void sendGifts();

}

接下来定义我和我的兄弟代理,均实现该泡妞接口

/**

* 委托类(幕后黑手我)

*/

public class Boy  implements FindLove {

@Override

    public void writeLovePaper() {

        System.out.println("小美,我老喜欢你了,我每天晚上想你,碎不着觉!");

    }

@Override

    public void sendFlowers() {

        System.out.println("花儿好像你啊,小美");

    }

@Override

    public void sendGifts() {

        System.out.println("送你两包辣条,小美,我爱你爱得吃辣条都想你");

    }

}

/**

* 代理类(傻兄弟苦力)

*/

public class BrotherProxy   implements FindLove {

    private Boy me;//实际背后执行者

    public BrotherProxy(Boy boy) {

        this.boy = boy;

    }

@Override

    public void writeLovePaper() {

       System.out.println("替我抄作业(我要写情书,没空写作业了!)");

        me.writeLovePaper();

        System.out.println("买饮料、烧烤、薯片!");

    }

@Override

    public void sendFlowers() {

        me.sendFlowers();

        System.out.println("回来路上,买饮料、烧烤、薯片!");

    }

@Override

    public void sendGifts() {

        me.sendGifts();

        System.out.println("回来路上,买饮料、烧烤、薯片!");

    }

}

这样我们就可以实现代理做苦力的事情了,是不是很舒服!那为什么又要有动态代理呢,想都不用想,肯定是静态代理弱鸡有缺陷啦,比如:

1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。如上的代码是只为Me类的访问提供了代理,但是如果还要为其他同学OtherClassMate类提供代理的话,就需要我们再次添加代理OtherClassMate的代理类。

      现在问题来了如果每个同学泡妞就要找一个自己的傻子同学做代理,哪里培养那么多听话的傻子呢?如果青少年不能泡到女神,国家光棍将越来越多,老龄化加重,生厂力急剧下滑,国力日渐萎靡。国家一看这样不行啊,现在国内单身狗这么多,得促进男女配对啊,就招募一帮爱国的傻子做公务员,让他们做爱情代理、道歉代理等,啧啧!这样我们每个人都能快乐得追求幸福了不是,哈哈哈!那这就是我们智能化后的代理---动态代理,在我们需要送情书之前,打个110:喂,我要泡妞,给来个跑腿!

下面说说动态

动态代理:代理类是在运行时生成的。也就是说 Java 编译完之后并没有实际的 class 文件,而是在运行时动态生成的类字节码,并加载到JVM中。

动态代理实质实际上是两组静态代理组合!其优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数

Java实现动态代理的大致步骤如下

1.定义一个委托类和公共接口(Boy和FindLove)。

2.自己定义一个类(调用处理器类,即实现InvocationHandler接口),这个类的目的是指定运行时将生成的代理类需要完成的具体任务(包括Preprocess和Postprocess),即代理类调用任何方法都会经过这个调用处理器类。

/*** 调用处理器

*/

public class FindLoveProxyimplements InvocationHandler {

private Objecttarget;//委托类对象

    public FindLoveProxy(Object target) {

this.target = target;

    }

@Override

    public Objectinvoke(Object proxy, Method method, Object[] args)throws Throwable {

System.out.println("抄作业");

        Object result = method.invoke(target, args);

        System.out.println("买零食、跑腿等!");

        return result;

    }

}

3.生成代理对象(当然也会生成代理类),需要为他指定(1)委托对象(2)实现的一系列接口(3)调用处理器类的实例。因此可以看出一个代理对象对应一个委托对象,对应一个调用处理器实例。

InvocationHandler handler =new FindLoveHandler(new Boy());

Class[] interfaces = {FindLove.class,Apology.class};//需要实现的接口

FindLove proxy = (FindLove) Proxy.newProxyInstance(null, interfaces, handler);//null表示采用默认的类加载器

proxy.writeLovePaper();

proxy.sendFlowers();

proxy.sendGifts();

实际项目中,如果我们想实现一个数据库的短连接,及在使用过后就断开,就使用代理(动静都行)来实现,动态代理方便一些,这里使用了lamda简化,代码如下。

public DataBaseCommands  getShortCommand(int database) {

    DataBaseConnection connection = getDatabaseConnection();

    RedisCommands target = connection.sync();

    return (RedisCommands) Proxy.newProxyInstance(DataBaseCommands.class.getClassLoader(), new Class[]{DataBaseCommands.class}

            , (proxy, method, args) -> {

Object result = method.invoke(target, args);

                connection .close();

                return result;

            });

}

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

推荐阅读更多精彩内容