一、JDK动态代理实现原理
- 动态代理类的生成是通过Proxy.newProxyInstance方法,如下面来自第一节的例子:
// 创建jdk动态代理
UserService jdkProxy = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(),
new Class[]{UserService.class}, handler);
- 进入Proxy.newProxyInstance源码
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
// 删除了影响阅读的异常捕获部分,并加上了响应注释。
// 拦截处理器不能为空 为空抛出异常
Objects.requireNonNull(h);
// 防御性拷贝 避免修改 interfaces数组对象的属性
final Class<?>[] intfs = interfaces.clone();
// 获取java安全管理器
final SecurityManager sm = System.getSecurityManager();
// 安全管理器不为空
if (sm != null) {
// 校验代理参数访问权限
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
// 1. 寻找或生成代理类信息 即 Class对象
Class<?> cl = getProxyClass0(loader, intfs);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 2. 根据类信息对象c1生成构造器
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;
}
});
}
// 3. 用构造器生成代理对象 将h拦截处理器设置到代理对象中
return cons.newInstance(new Object[]{h});
}
我们看到关键代码注释 1、2、3 。得知生成代理类逻辑: 生成代理类的class对象c1–> 根据class对象c1生成类构造器对象cons–> 根据构造器cons生成代理。
- 进入注释1的源码查看如何生成代理类的class信息
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// 接口数组超过65535抛出异常
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 如果通过给定类加载器定义并实现指定接口的代理类的class对象存在,则直接返回。
// 否则通过ProxyClassFactory创建代理类的class对象
return proxyClassCache.get(loader, interfaces);
}
我们看到 proxyClassCache.get 方法是生成代理类class对象的关键。
- 进入proxyClassCache.get方法查看如何生成代理类的class信息
public V get(K key, P parameter) {
// 忽略其他代码我们只看 创建代理Class的代码
// 创建subkey
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 根据subkey 找回可能的被存储的supplier
Supplier<V> supplier = valuesMap.get(subKey);
V value = supplier.get();
// 返回代理类Class对象
return value;
}
这里用到了缓存机制获取代理类Class对象,我们在第三节进行详细讲述。
二、为什么JDK动态代理必须实现接口
- 因为JDK动态代理类继承了Proxy类,Java又是单继承的,所以被代理对象只能通过实现接口,让代理对象生成相应接口的实现。
那么,问题来了。为什么JDK动态代理要继承Proxy类呢?留给大家思考!
三、JDK生成的动态代理类实例
第一节生成的动态代理类
public final class $Proxy0 extends Proxy implements UserService {
private static Method m1;
private static Method m2;
private static Method m0;
private static Method m3;
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 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);
}
}
public final void addUser() throws {
try {
super.h.invoke(this, m3, (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"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m3 = Class.forName("com.java24k.example.service.UserService").getMethod("addUser");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
- 调用动态代理类的任何方法,都是调用它的父类的拦截处理器的相应方法。
- 拦截处理器持有真实对象,在拦截处理器的invoke方法中回调用真实对象的相应方法。