jdk动态代理是基于接口实现的代理,而非继承
要对一个类进行扩展,无非就是继承或者是实现接口两种方式,为什么jdk的代理类,一定要基于接口实现?
直接先说结论:之所以必须要使用继承,是因为jdk为我们生成的代理类,默认继承了proxy类,所以,我们只能实现目标接口
打印代理类
jdk动态代理,是需要有一个InvocationHandler接口的实现类,在实现类中,我们可以通过Proxy.newProxyInstance()来生成代理类
Proxy.newProxyInstance()方法,最终会调用到
java.lang.reflect.Proxy.ProxyClassFactory#apply
来生成代理对象,调用链比较简单,就不再叙述了
在这个方法中,我们可以发现,有一行至关重要的代码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
就是这里,生成了代理类,然后再调用了一个native方法,最后返回了一个class对象,那我们可以在代码中,设置属性,把这个代理类打印出来
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
只需要这一行代码,就可以打印当前的代理类信息
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import com.design.demo.proxy.dynamic.Sale;
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 Sale {
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 saleBook() 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.design.demo.proxy.dynamic.Sale").getMethod("saleBook");
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类,由于Java是单继承,所以,对于要代理的对象,我们只能通过实现接口的方式来实现
通过对代理类的分析,我们可以发现,在代理类中注入了一个InvocationHandler对象,这个invocationHandler对象,就是我们自己的实现类,因为我们在调用 Proxy.newProxyInstance()方法的时候,需要指定一个invocationHandler对象,所以,在我们调用目标方法(saleBook)的时候,其实会调用到invocationHandler的invoke()方法,我们可以在invoke方法中,进行自定义逻辑的处理
结论
所以,一句话解释为什么jdk动态代理必须要通过接口实现,是因为jdk在底层生成代理对象的时候,就默认继承了Proxy类,所以只能通过接口的方式,来对目标方法进行代理