代理模式
Proxy
根据下面的文章学习代理模式
https://juejin.im/post/5a99048a6fb9a028d5668e62#heading-0
https://juejin.im/post/5dec590551882512480a76e3
我们的目标:增强方法,尤其是在一些封装好,不能直接修改原方法的情况下,对方法进行增强。
解决方案
a)继承
最直观解决方案
b)聚合(静态代理)
与继承同样是java类五大关系之一
利用多态的特性
典型的静态代理
静态代理至少有以下两个局限性问题:
- 如果同时代理多个类,依然会导致类无限制扩展
- 如果类中有多个方法,同样的逻辑需要反复实现
比如假如要增强100个方法,就要起码写100个代理类
那么,我们是否可以使用同一个代理类来代理任意对象呢?
起码一个特定代理类能给任意方法增强一个特定功能?
c)动态代理
难理解,因为方式比较大胆,
是否可以使用同一个类(例如:TimeProxy)来计算任意对象的任一方法的执行时间呢。
这个部分需要一定的抽象思维,我想,你脑海中的第一个解决方案应该是使用反射。反射是用于获取已创建实例的方法或者属性,并对其进行调用或者赋值。很明显,在这里,反射解决不了问题。
但是,再大胆一点,如果我们可以动态生成TimeProxy这个类,并且动态编译。然后,再通过反射创建对象并加载到内存中,不就实现了对任意对象进行代理了吗?
个人理解:运行时再生成代理类,然后再生成Proxy对象。以前手写的 TimeProxy.java用 Proxy .java 自动生成了,虽然Proxy .java看着也很复杂
第一步:(动态)生成TimeProxy源码
第二步:(动态)编译TimeProxy源码
第三步:加载到内存中并创建对象
通过以上三个步骤,我们至少解决了下面两个问题:
-
不再需要手动创建TimeProxy
(手动创建了Proxy类)
-
可以代理任意实现了Flyable接口的类对象,并获取接口方法的执行时间
(就是给任意实现了Flyable接口的类对象所实现的接口方法增加了一个功能)
现在的问题
- 一个Proxy类针对一个功能(记录方法运行时间)动态生成,想增强别的功能得再写个Proxy类
- Proxy类里写死了生成的类的接口类型(改成由 newProxyInstance(Class inf) 传递参数确定接口类型就行就可以了)
第四步:增加InvocationHandler接口
public interface InvocationHandler {
void invoke(Object proxy, Method method, Object[] args);
}
- proxy => 这个参数指定动态生成的代理类,这里是
TimeProxy
- method => 这个参数表示传入接口中的所有Method对象
- args => 这个参数对应当前method方法中的参数
为此,我们需要在Proxy.newProxyInstance()方法中做如下改动:
- 在newProxyInstance()方法中加一个参数传入InvocationHandler
- 在生成的代理类中增加成员变量handler
- 在生成的代理类方法中,调用invoke方法
然后实现InvocationHandler接口, MyInvocationHandler 类, invoke方法里实现要添加的功能。
tip:因为要用到反射,反射里也有invoke方法,不要搞混 !
其实Proxy和InvocationHandler接口不用自己写,JDK自带,跟那个博客里写的差不多,只有些细节上的区别,比如为了方便链式编程返回值返回对象。