JDK动态代理详细解析
作者:一码评川
一、说明
在Java的动态代理机制中,有两个重要的类和接口,一个是InvoInvocationHandler(接口)、Proxy(类),这一个类和接口是我们动态代理所必须用到的。
优点:
- 对于实现了接口的类,可以直接使用基于接口的动态代理进行代理,非常方便
- 代理类和被代理类都必须实现同一个接口,能够实现对被代理对象的方法调用进行统一管理。
- 性能上:在老版的jdk,jdk代理生成的类速度快,通过反射调用慢,cglib是jdk代理速度的10倍左右,jdk在版本每次升级都会有很大的性能提升,cglib停滞不前,jdk7 8的动态代理性能在1万次实验中比cglib要快20%左右
- jdk动态代理如果目标类未实现接口则无法代理,cglib是通过继承的方式来动态代理,若目标类被final关键字修饰,则无法使用cglib做动态代理
缺点:
- 只能代理实现了接口的类,对于没有实现接口的类无法使用此种方式进行代理。
- jdk动态代理只提供实现接口的目标类代理,不支持没有实现接口的目标类的代理。如果目标类没有实现接口,只能用cglib代理
二、主要类方法的说明
InvocationHandler接口
每个动态代理类都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler接口的invoke方法来进行调用。
InvocationHandler接口的invoke方法
- Object invoke(Object proxy, Method method, Object[] args) throws Throwable
- proxy: - 指代我们所代理的那个真实对象
- method: - 指代的是我们所要调用真实对象的某个方法的Method对象
- args: - 指代的是调用真实对象某个方法时接受的参数
**proxy存在的意义:**
1. 可以使用反射获取代理对象的信息(也就是proxy.getClass().getName())。
2. 可以将代理对象返回以进行连续调用,这就是proxy存在的目的,因为this并不是代理对象。
Proxy 类
Proxy类的作用就是用来动态创建一个代理类对象的类,它提供了许多的方法,但是我们用的最多的就是newProxyInstance这个方法
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
- loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
- interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
- h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
打印代理的类:
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
三、关键步骤
创建InvocationHandler实现类
public class MapperProxy<T> implements InvocationHandler { private Class<T> proxyInterface; //这里可以维护一个缓存,存这个接口的方法抽象的对象 MapperProxy(Class<T> proxyInterface){ this.proxyInterface = proxyInterface; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("执行前..."); Constructor constructor = proxyInterface.getConstructor(); Object o = constructor.newInstance(); method.invoke(o,args); System.out.println("执行后"); return null; } }
通过 Proxy.newProxyInstance() 创建代理实例
Fly fly = (Fly) Proxy.newProxyInstance(MyFly.class.getClassLoader(),new Class[]{Fly.class, Fly.Fly2.class},new MapperProxy<>(MyFly.class));
- 创建代理类- Class<?> cl = getProxyClass0(loader, intfs);
- 获取有参构造器 Constructor<?> cons = cl.getConstructor(constructorParams);这里的参数就是InvocationHandler
- 通过构造器创建代理实例-参数就是方法的第三个参数
分析生成的代理类
结论
- 代理类会继承Proxy ,这里也就解释了为什么通过JDK生成的代理无法代理非接口实现类了
- 代理类实现了传入的所有接口类型
调用代理类的doFly()
这里会调用 super.h.invoke(this, m3, (Object[])null);
super.h就是我们再创建代理对象是传入的MapperProxy,所有这里会执行MapperProxy.invoke方法(在这里我们就可动态的对该执行方法进行增强)
到此这篇关于JDK动态代理详细解析的文章就介绍到这了,更多相关JDK动态代理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!