-
若自己实现代码增强,则需要为每个目标对象单独编写一个代理Class对象然后用类加载器加载,实例化,再调用,这样每个目标对象都得单独地编写代理Class对象以达到目的(即静态代理)。若是每一个目标对象都需要我们自己写一个相应的代理类来实现增强,那工作量将十分惊人,因此我们需要找到其中的相似点,提取出来,对其进行增强,才能减少我们的负担(为什么选用动态代理的原因)。
-
为了减少代理类地编写,我们类的消息一般都由Class对象在JVM方法区中被加载(反射和new都是),若想不编写代理class还要有目标类的信息,自然而然地可以想到接口,若能对接口进行动态代理,则可将实现该接口并调用该接口中的方法(可能不止实现一个接口)的目标类归为一类进行代码编写(这就是为什么要使用动态代理的原因),但是,接口并不能实例化
-
但java.lang.reflect.Proxy类有个getProxyLoader(ClassLoader,interfaces)方法,只要你给他传入类加载器和一组接口,它就能给你返回代理Class(并且可以带有构造器进行实例化)
- 有了代理Class(代理Class为代理类->数据结构,代理对象为实例化的对象),我们可以通过该对象得到有参的构造器(基于InvocationHandle接口),我们就可以反射创建实例了,而基于上述接口的构造器可以基于实例化的InvocationHandle接口的对象实例化,使得代理对象通过handler对象中的invoke方法去增强目标对象(InvocationHandle接口是一个规范,代理对象中会有成员变量去接收它,并为他的proxy、method、args等传参,为了便于设计把他提取出来,将功能模块化)
InvocationHandler handler = new DynamicProxy(realSubject);
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: 指代我们所代理的那个真实对象
method: 指代的是我们所要调用真实对象的某个方法的Method对象
args: 指代的是调用真实对象某个方法时接受的参数
可能会以为返回的这个代理对象会是Calculator类型的对象,或者是InvocationHandler的对象,结果却不是,首先我们解释一下为什么我们这里可以将其转化为Subject类型的对象?原因就是在getPorxyClass这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是Subject类型,所以就可以将其转化为Subject类型了。
同时我们一定要记住,以上获取代理Class、得到有参构造函数、实例化后创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。