JDK动态代理 Proxy#newProxyInstance源码分析
本篇是结合JDK动态代理的实现----详细易懂继续讲的:
下面是Proxy#newProxyInstance的源码,写注释的地方就是我们要关注的地方:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
{
Objects.requireNonNull(h);
//复制一份接口的Class对象
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
//获取代理类(!!!这里代理类,不是代理对象)
Class<?> cl = getProxyClass0(loader, intfs);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//通过Class对像拿到相应的构造器(这里的参数就是InvocationHandler)
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//通过构造器创建代理对象并返回
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
如果我们要解开上面的疑惑,我们就需要看一看生成的代理对象的它的类文件是什么样的,接下来我们先打个断点debug一下看看:
可以看到生成的代理类的名字,通过名字找到该class文件,对其进行反编译,如下:
package com.sun.proxy;
import com.zwh.proxy02.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void doLogin() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.zwh.proxy02.Subject").getMethod("doLogin");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
分析:代理类继承了Proxy类,并且实现了我们案例中定义的Subject接口,并且重写了doLogin()方法,着重看一下该方法的实现:
可以看到doLogin()方法就是执行的super.h.invoke(…)方法,m3就是方法名;
这里的super.h是什么?super就是Proxy类吧,那就回到Proxy类中看看h是什么:
h就是InvocationHandler,并且通过有参构造器进行赋值的;那么我们追溯一下这个有参构造器是在哪被使用的。在$Proxy0这个生成的代理类的构造方法中调用了Proxy的有参构造器:
所以这里的h就是$Proxy0有参构造器中的InvocationHandler类型的var1,那么这个var1是谁呢?
就去Proxy#newProxyInstance的源码中去找,因为$Proxy0的实例是Proxy的newProxyInstance方法创建的,那么在newProxyInstance方法中会存在对$Proxy0构造器的调用:
在newProxyInstance方法的形参中有个InvocationHandler类型的h,接着看newProxyInstance方法里面哪地方用到了这个h:
破案了!!!$Proxy0类中doLogin()中的super.h.invake(…),其实就是我们在这传入的MyInvocationhandler中的invoke()方法:
从以上分析就可以明白了,为什么在使用代理对象时,执行的是我们实现的InvocationHandler中的逻辑了;
(以上分析有异议的地方欢迎大佬们指正,感谢!)