JDK动态代理
这里我写下截图里面的接口方法
这就是为啥写这骗文章的原因,也是一时兴起 见谅见谅
这里就是动态生成了TypeServiceImpl这个类的代理对象,
$proxy36就是typeServiceImpl这个类的代理对象
args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。
下面我们来分析一下, jdk底层到底搞了啥就生成了代理类:
首先我们从获取代理类的方法中的Proxy.newProxyInstance
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread()
.getContextClassLoader(), target.getClass().getInterfaces(),
this);
}
点进去, 可以在Proxy 中看到该静态方法的签名:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
1
2
3
4
该方法的注释:
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.返回一个特定接口的代理类的实例, 代理类对象可以分发method调用到专门的调用处理器。
1
待会儿就能理解这句话的含义了。根据javaDoc 得出:
第一个参数为一个类加载器, 就是指定一个类加载器来加载所生成的代理类的字节码而已。
第二个参数为代理类要去实现的接口
第三个参数就是我们所定义的invocation handler 我们毕竟刚才传递的是this 嘛
再看整个方法里面的核心逻辑(删除部分校验逻辑):
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
//接口克隆了一份
final Class<?>[] intfs = interfaces.clone();
/*
* Look up or generate the designated proxy class.
* 查询或着生成指定的代理类, 之所以查询是因为, 之前曾经生成
* 的代理类可能被缓存了。 在这里只是生成了代理类class对象
* 而已
*/
Class<?> cl = getProxyClass0(loader, intfs);
//在这里根据class对象拿到代理类构造方法
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;
}
});
}
//这里真正的创建了 一个代理对象的实例,
//我们留一个疑问, 为什么传过去一个包含h的数组???
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
。。。。。
}
其中newInstance只是调用Constructor.newInstance来构造响应的代理类的实例
我们接下来把getProxyClass0() 方法逻辑拉出来
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
return proxyClassCache.get(loader, interfaces);
}
可以看到Cache字眼了, 如果缓存中存在代理类, 直接从Cache取出, 否则生成并缓存。这里有意思的是如何进行的缓存? 如何判断的代理类是否是同一个?