小白学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;

            });

}

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容