文章插图
Proxy源码
来看下Proxy 源码,当我们 newProxyInstance(…) 时,首先系统会进行判空处理,之后获取我们实际的 Proxy 代理类 Class 对象,再通过一个参数的构造方法生成我们的代理对象 p(p : 返回值),这里能看出来 p 是持有我们的对象 h 的 。注意 cons.setAccessible(true) 表示,即使是 cl 是私有构造,也可以获得对象 。源码见下:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNon(h);
final Class<?> intfs = interfaces.clone;
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
...
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers)) {
cons.setAccessible(true);
// END Android-removed: Excluded AccessController.doPrivileged call.
}
return cons.newInstance(new Object[]{h});
...
}
其中 getProxyClass0(…) 是用来检查并获取实际代理对象的 。首先会有一个65535的接口限制检测,随后从代理缓存 ProxyClassCache 中获取代理类,如果给定的接口不存在,则通过 ProxyClassFactory 新建 。见下:
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
存放代理 Proxy.class 的缓存 proxyClassCache,是一个静态常量,所以在我们类加载时,其就已经被初始化完毕了 。见下:
private static final WeakCache<ClassLoader, Class<?>, Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory, new ProxyClassFactory);
Proxy 提供的getInvocationHandler(Object proxy)方法和 invoke(…) 方法很重要 。分别为获取当前代理关联的调用处理器对象 InvocationHandler,并将当前Proxy方法调用调度给 InvocationHandler 。
是不是与上面的代理思维很像,至于这两个方法何时被调用的,推测是写在了本地方法内,当我们调用 proxy.request 方法时(系统创建Proxy时,会自动 implements 用户传递的接口,可以为多个),系统就会调用 Proxy invoke 方法,随后 proxy 将方法调用传递给 InvocationHandler 。
public static InvocationHandler getInvocationHandler(Object proxy)
throws IllegalArgumentException
{
/*
* Verify that the object is actually a proxy instance.
*/
if (!isProxyClass(proxy.getClass)) {
throw new IllegalArgumentException("not a proxy instance");
}
final Proxy p = (Proxy) proxy;
final InvocationHandler ih = p.h;
return ih;
【一文带你弄懂 Java 动态代理】}
// Android-added: Helper method invoke(Proxy, Method, Object[]) for ART native code.
private static Object invoke(Proxy proxy, Method method, Object[] args) throws Throwable {
InvocationHandler h = proxy.h;
return h.invoke(proxy, method, args);
}
文章插图
ProxyClassFactory
重点是ProxyClassFactory 类,这里的逻辑不少,所以我将ProxyClassFactory 单独抽出来了 。能看到,首先其会检测当前 interface 是否已被当前类加载器所加载 。
Class<?> interfaceClass = ;
try {
interfaceClass = Class.forName(intf.getName, false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
之后会进行判断是否为接口 。这也是我们说的第二个参数为何不能传基类或抽象类的原因 。
if (!interfaceClass.isInterface) {
throw new IllegalArgumentException(
interfaceClass.getName + " is not an interface");
}
之后判断当前 interface 是否已经存在于缓存cache内了 。
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != ) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName);
}
检测非 public 修饰符的 interface 是否在是同一个包名,如果不是则抛出异常:
推荐阅读
- 带你读懂古树茶,书剑说普洱书剑古茶冰岛地界阳光大晒场
- 带你了解雨前茶,雨前茶是什么时候
- 太极运动的奥秘 带你了解太极运动
- 带你探索纯料之谜,深度探索台北茶文化
- 喝粤式早茶,手敲桌面3下啥意思?弄懂6大规矩,服务员:这是老广
- 一分钟带你读懂五线谱
- 学习python你必须弄懂的 Python、Pycharm、Anaconda 三者的关系
- 都是酱油,生抽、味极鲜、一品鲜区别挺大,弄懂了再买不吃亏
- 怎样选择数据库?一文看懂数据库分类
- 陈年老茶和新茶的区别,弄懂普洱茶生茶和熟茶的区别