为什么JDK的动态代理只能实现接口的代理?
我们通过JDK动态代理生成的代理对象的类型实际是$Proxy0
(这个名字后面的0是编号,有多个代理类会一次递增)类,该类继承了Proxy类,所以只能对接口进行代理。Java的继承机制注定了这些动态代理类们无法实现对类的动态代理。
public final class $Proxy0 extends Proxy
动态代理底层实现原理?
Proxy.newInstance(ClassLoader loader,
);
Class<?>[] interfaces,
InvocationHandler h
(其中,所有对动态代理对象的方法调用都会被转向到InvocationHandler
接口的实现上)
通过该方法,我们生成代理对象。
看下该方法源码:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{
if (h == null) {
throw new NullPointerException();
}
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*查找(缓存中查找,如果没有就生成)或生成指定的代理类*/
Class<?> cl = getProxyClass0(loader, intfs);
/*用指定的调用处理程序调用它的构造函数.*/
try {
//获得类的构造函数
final Constructor<?> cons =cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
//当需要代理的类实现了一个非public的接口时,因为这样的接口需要特殊的权限,因此调用doPrivilege(native 修饰的方法)创建代理实例。
return AccessController.doPrivileged(newPrivilegedAction<Object>() {
public Object run() {
return newInstance(cons,ih);
}
});
} else {
return newInstance(cons,ih);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}
可以看到,获得代理类的代码是
Class<?> cl = getProxyClass0(loader,intfs);
并由此获得代理类的构造函数
Constructor<?> cons =cl.getConstructor(constructorParams);
生成代理类的实例返回给该方法的调用者。
return newInstance(cons,ih);
/*
底层获得代理类的过程大致是:
1.创建代理类的源码;
2.对源码进行编译成字节码;
3.将字节码加载到内存;
4.实例化代理类对象并返回给调用者;
*/
jdk为我们的生成了一个叫$Proxy0(这个名字后面的0是编号,有多个代理类会一次递增)的代理类,这个类文件是放在内存中的,我们在创建代理对象时,就是通过反射获得这个类的构造方法,然后创建的代理实例。
我们可以把nvocationHandler看做一个中介类,中介类持有一个被代理对象(真实对象),在invoke方法中调用了被代理对象的相应方法。通过聚合方式持有被代理对象的引用,把外部对invoke的调用最终都转为对被代理对象的调用。
代理类调用自己方法时,通过自身持有的中介类对象来调用中介类对象的invoke方法,从而达到代理执行被代理对象的方法。也就是说,动态代理通过中介类实现了具体的代理功能。
参考文章:java动态代理实现与原理详细分析