jdk动态代理—如何执行到invoke方法
先写一个动态代理demo。
接口:
public interface Inter {
void test();
}
目标类,即需要被代理的类:
/**
* 要被代理的类
*/
public class InterImpl implements Inter {
@Override
public void test() {
System.out.println("======执行了test方法======");
}
}
写一个类生成代理对象:
/**
* 这个类生成代理对象
*/
public class ProxyFactory implements InvocationHandler {
/**
* 要代理的对象
*/
private Object target;
/**
* 构造器传入要代理的对象
*/
public ProxyFactory(Object target) {
this.target = target;
}
/**
* 实现InvocationHandler接口的invoke方法
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target,args);
}
/**
* 这个方法生成并返回代理对象
*/
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
}
测试一下:
public class Test {
public static void main(String[] args) {
//要被代理的对象(目标对象)
Inter target = new InterImpl();
//传入目标对象,生成代理对象
Inter instance = (Inter) new ProxyFactory(target).getProxyInstance();
instance.test();
}
}
结果显然没有问题:
======执行了test方法======
分析:
在主方法输出instance.getClass()
System.out.println(instance.getClass());
输出:
class com.sun.proxy.$Proxy0
可以看出,instance就是动态生成的代理对象,属于com.sun.proxy.$Proxy0
这个类。
$Proxy0
这个类是在内存中动态生成的,我们可以通过反编译查看源码。
主函数中添加一句:
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
现在主函数长这个样子:
public static void main(String[] args) {
//这句要放在生成代理对象之前,目的是为了生成$Proxy0.class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//要被代理的对象(目标对象)
Inter target = new InterImpl();
//传入目标对象,生成代理对象
Inter instance = (Inter) new ProxyFactory(target).getProxyInstance();
System.out.println(instance.getClass());
instance.test();
}
执行之后,在项目下多了com文件夹,在com\sun\proxy
下生成了$Proxy0.class
文件,用idea打开即可自动反编译。
贴上源码:
public final class $Proxy0 extends Proxy implements Inter {
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 test() 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.example.Inter").getMethod("test");
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
的newProxyInstance
函数,看看代理对象是如何被创建的。
//参数1:类加载器
//参数2:接口列表
//参数3:InvocationHandler
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/**
* 第一步:生成指定的代理类
* getProxyClass0()方法根据我们传入的类加载器和接口,
* 动态生成了$Proxy0类
*/
Class<?> cl = getProxyClass0(loader, intfs);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
/**
* 第二步:获得$Proxy0的构造方法,传入参数类型
*/
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);
}
}
总结一下:
newProxyInstance
创建代理对象大致可分为三个步骤:
-
Class<?> cl = getProxyClass0(loader, intfs);
debug看出,这句话返回的正是代理对象的类
$Proxy0
。 -
final Constructor<?> cons = cl.getConstructor(constructorParams);
其中,
constructorParams
是参数类型,代表构造器需要传入InvocationHandler
对象。private static final Class<?>[] constructorParams = { InvocationHandler.class };
debug一下,这句返回的是
$Proxy0
的构造器,参数是InvocationHandler
。 -
return cons.newInstance(new Object[]{h});
最后,通过反射返回
$Proxy0
的实例,即代理对象。其中
h
正是我们调用newProxyInstance
函数时传入的第三个参数。
至此,newProxyInstance
方法执行完毕,返回了一个代理对象。
通过代理对象调用方法:
instance.test();
在代理对象调用方法时,我们已经知道instance
是$Proxy0
的实例,所以instance
调用的test
方法是$Proxy0
中的test
方法。
$Proxy0
中的test方法如下:
public final void test() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
其中执行方法的语句为:
super.h.invoke(this, m3, (Object[])null);
$Proxy0
类继承了Proxy
,实现了我们自定义的接口Inter
,其中super.h
即Proxy
的h
,即InvocationHandler
。
Proxy
类中聚合了InvocationHandler
。protected InvocationHandler h;
故这句话实际在调用InvocationHandler
的invoke
方法,而这个方法,就是我们之前实现的方法。
在我们自定义的方法里,通过反射,就执行到了目标对象的test方法~
为什么jdk动态代理必须是接口
原因很简单,就是因为我们生成的代理类$Proxy0
已经继承了 Proxy
,由于java的单继承多实现,无法继承别的类~