上篇文章写JDK动态代理实现的方式,其中涉及到一个重要的接口InvocationHandler和一种重要的类Proxy。JDK动态代理实现的原理是在根据被代理对象的接口,一个类加载器和InvocationHandler对象,动态生成一个代理类。这个类到底是什么样的呢?
public static void main(String[] args) throws IOException {
//将JDK生成的代理类保存到本地
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
int array[] = {10, 8, 12, 31, 5, 1, 7, 8, 30, 10, 15};
Sort sort = new QuickSort();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(sort);
Sort sortProxy = (Sort)Proxy.newProxyInstance(myInvocationHandler.getClass().getClassLoader(), sort.getClass().getInterfaces(), myInvocationHandler);
sortProxy.sort(array);
}
在代码前加上这行代码System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")可以将JVM动态生成的代理类保存在本地,在com/sun/proxy目录下面我们可以找到生成的代理类$Proxy0.class。我可以同时使用JD(java 反编译软件)将该代理给进行反编译。反编译的代码如下:
public final class $Proxy0 extends Proxy implements Sort
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void sort(int[] paramArrayOfInt)
{
try
{
//调用的是InvocationHandler实例的Invoke方法,在该方法中进行通过反射机制,调用了目标对象的sort方法。
this.h.invoke(this, m3, new Object[] { paramArrayOfInt });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
//静态初始化,初始接口中m1,m2,m3,m0属性,
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("test.Sort").getMethod("sort", new Class[] { Class.forName("[I") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
根据源码可知,代理类继承了Proxy实现了和目标对象类相同的接口(Sort),并且在静态初始化时将Sort接口中的方法(sort)通过Method类型成员变量m3保存。
动态代理代码执行的流程:
- 调用代理的的方法。(因为代理类实现了和目标对象的类相同的接口,所以对于用户来说就像是调用目标类方法一样)
- 代理类中的方法调用InvocationHandler的invoke方法。
- 执行用户的增强逻辑(可有可无)。
- 通过反射调用目标对象的目标方法(调用时传入目标方法)。
- 执行用户增强逻辑(可有可无)。
- 返回调用结果。
注意:利用JDK实现动态代理时,被代理的对象必须实现了接口,如果没有实现接口是无法生成代理类的,并且接口数量不能超过65535.
扩展:Spring框架在实现AOP是同时支持JDK动态代理技术和CGLIB的方式。
这两种方式实现动态代理是有所区别的,CGLIB是一种代码生成技术,实现动态代理时不要求目标对象的类不一定要实现接口的,因为CGLIB是同过直接继承目标对象的类并重写方法实现的。