一、说明
在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方法(在这里我们就可动态的对该执行方法进行增强)