代理模式
意图:为其他对象提供一种代理以控制对这个对象的访问。
说白话就是在不侵入原来功能的基础上,附加一些功能。例如在执行方法前后打印日志啊,统计一下执行方法次数啊,一些异常处理啊..
1.什么是代理模式
我看来整个代理模式大同小异就是这重要的三者 1. 被代理类 2.代理类 3.需要被增强的方法继承的接口
这里用一个大学时老师讲的例子举例,少说废话上代码
先简单定义一个接口Animal,代表所有动物,其中run()方法作为被代理方法
我们定义一个小鸟继承Animal和run()方法
如果这就是我们正常的业务需求,创建小鸟然后执行run()方法就可以了。
突然有天加需求,需要记录小鸟的run()方法每天会执行多少次,如果不侵入原来代码逻辑去处理呢? 如果以后会有更多动物都需要记录run()调用次数如何处理?
我们创建了一个Animal的代理类 AnimalProxy,
通过构造方法传入被代理对象animal,
重写run()方法,执行animal原本的run()逻辑,同时加上附加功能,
最后执行printCount() 打印调用次数
没有侵入原来代码,完成了调用计数,还易于扩展(无论是Dog Cat Elephent 啥都能代理)
这tnd的其实就是静态代理
大学课上还问过老师为啥代理类一定要继承Animal接口,不继承不是也完全可以实现的吗。 现在想想设计者大概是为了是统一管理,代理前代理后都是run()方法,这显得很专业!
2.静态代理与动态代理
上一节详细介绍了静态代理的实现,但是缺点也很明显,
1 根据这种形式,被代理的方法一定要继承于接口实现,并且代理类一定要继承该接口。 AnimalProxy如果不继承Animal接口那就没得玩了
2 这次需求我们做各种动物的方法计数,下次需求我们做飞机大炮的方法调用计数怎么办? 你说你改改代理类的构造入参,改改接口继承关系还能接着玩,那下下次呢? 下下下次? 一直改代码肯定自闭啊
3 第三点和上一点差不多,如果后续这个run()方法入参变化了,返回值变了等等,被代理类 代理类都需要反复修改,肯定难受
有没有方便灵活的办法解决这些问题? 有,动态代理
静态代理动态代理我认为最大的区别在于代理类的生成
静态代理属于编译之前,我手动把代理类写好,然后编译成.class文件执行
动态代理属于运行时,利用反射机制,动态的生成代理类
3.JDK动态代理
先上demo
在之前的例子上,Animal接口 与Bird类均不动,只在AnimalProxy做文章
AnimalProxy继承于InvocationHandler,
重写invoke()方法,用来做增强附加功能的具体实现,
定义了一个Object任意被代理target,
定义bind()方法,用来绑定被代理的对象。
结果和静态代理相同,只是这里的角色有些改变
被代理类和接口没变,多了一个工具人的身份,
工具人负责写好增强功能效果,绑定好被代理类,动态的创建出一个代理类来
问几个问题,bind()中传入的对象应该具有什么条件?
为什么传入了一个对象,就能直到为哪个方法实现了增强? 并且能动态的生成继承了同一个接口的代理对象?
源码之下无秘密,一切就藏在 Proxy.newProxyInstance()源码中(玩转个屁)
。。。未完待续
4.cglib动态代理
5.Spring AOP中动态代理
Spring代理其实是对JDK动态代理和CGLIB代理进行了封装,并且引入了AOP的概念,同时引入了AspectJ中的一些注解:@pointCut @After 等。