动态代理
java动态代理的前提条件是,代理对象必须实现了某个接口。如果没有实现接口,就需要用cglib代理。
构造代理类需要三个信息:
- 目标类的类加载器
- 目标类实现的接口
- 代理处理句柄
生成的代理类 继承Proxy 并且 实现目标类的接口
然后调用Proxy构造方法,设置处理句柄 InvokeHandler h
假设目标类: TargetImp
目标类接口: Target
自定义处理句柄: MyInvoke implements InvocationHandler
那么代理类 $taget0 大概就是这样的结构:
$taget0 extends Proxy implements Target {
Medhod m1;
Medhod m2;
...
Medhod m1;
//.....
}
InvocationHandler 设置时通过调用Proxy的newProxyInstance(Object ,Method , Object[] )
然后该方法内部调用Proxy的构造方法,Proxy(InvocationHandler h)设置处理句柄.
其实所有的代理处理逻辑都在InvocationHandler 的 invoke方法中。
$taget0 执行方法其实就是调用invoke(this,m1,args)类似这样
$taget0内部会对应每一个方法生成一个方法的句柄 Method m1 ...
然后执行时会调用父类InvocationHandler属性的invoke方法
super.h.invoke(this,m1,args);
实例:
接口 Target.java
package proxy.dynamic; public interface Target { public void say(); public void play(); }
目标类 TargetImp.java
package proxy.dynamic; public class TargetImp implements Target{ public void say(){ System.out.println("Target say()"); } public void play(){ System.out.println("Target play()"); } }
处理逻辑 MyInvoke.java
package proxy.dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvoke implements InvocationHandler{ Object target; public MyInvoke(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName() == "say") { System.out.println("begain say()"); } if (method.getName() == "play") { System.out.println("begain play()"); } Object res = method.invoke(target, args); if (method.getName() == "say") { System.out.println("end say()"); } if (method.getName() == "play") { System.out.println("end play()"); } return res; } }
测试类 DynamicProxy.java
package proxy.dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class DynamicProxy { public static void main(String[] args) { final Target target = new TargetImp(); InvocationHandler myInvoke = new MyInvoke(target); Target targetProxy = (Target) Proxy.newProxyInstance(TargetImp.class.getClassLoader(),TargetImp.class.getInterfaces(),myInvoke); targetProxy.say(); targetProxy.play(); } }
执行结果:
begain say()
Target say()
end say()
begain play()
Target play()
end play()
然后我们进一步看看代理生成的类在哪,在虚拟机中是什么样的结构
这里用jdk提供的虚拟机调试工具 hsdb 调试
先来看一下生成的类:
我们看到生成了一个代理类$Proxy0, 下面看一下类的结构
这里显示了:
- $Proxy0 的父类
- 实现的接口
- 一些方法的句柄,
- methods部分的一些方法被重写,内部会调用 invoke
- 最先面是常量池的信息
再继续,我们在深入的看一下 $Proxy0 产生的实例包含了什么信息
可以看到$Proxy0实例 关联了一个 MyInvoke实例 。然后MyInvoke实例 关联了 目标对象 TargetImp
总结:
动态代理就是根据目标对象,产生一个 和目标对应拥有共同接口 且 继承了Proxy类的 类。
具体代理逻辑,交给InvocationHandler 的实现类去处理。