深度解析jdk动态代理: 从源码 到 字节码 到 自己手写动态代理

作者

  • B站讲课: 李滋芸
  • 微信公众号: 小豆的奇思妙想
  • 视频讲解: https://www.bilibili.com/video/BV1t44y1B77P
​注意
本篇文章,讲解非常详细.已经到了字节码层面.
内容和篇幅较多.请有耐心,并按照源码依依查

反编译查看: 动态代理生成的字节码

在这里插入图片描述

  • 分析: 所有的方法处理,都转发给InvocationHandler

源码分析: Proxy.newProxyInstance()

  • 作用: 安全校验,Class反射构造器创建对象
  1. 获取所有接口
  2. 获取动态对象的Class
  3. 反射获取构造器
  4. 通过构造器,创建对象
  • 核心: Class cl = getProxyClass0(loader,infs)
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
{
        // lzy分析: null判断
        Objects.requireNonNull(h);
        // lzy分析: 获取所有需要动态代理的接口
        final Class<?>[] intfs = interfaces.clone();
        // lzy分析:  系统安全校验器
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            // lzy分析: 安全校验
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        // lzy分析(核心): 生成代理类的Class对象
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                // lzy分析: 安全校验
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            // lzy分析: 反射获取构造器
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            // lzy分析: 判断构造方法权限修饰符.如果没有权限,强制访问.
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            // lzy分析: 通过构造方法创建对象.
            // h是InvocationHandler,代理对象的处理器.
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

源码分析: Proxy.getProxyClass0(loader,infs)

        // lzy分析: 接口个数限制
        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
        // lzy分析: 通过类加载器loader 和 所有代理接口interfaces,从缓存中获取
        return proxyClassCache.get(loader, interfaces);

源码分析: WeakCache.get()

  • 作用: 获取工厂,利用工厂创建代理对象
  1. 类加载获取,已经加载的接口
  2. 所有接口进行Hash唯一标识
  3. 准备创建工厂
  4. 通过工厂创建代理对象
  5. 重试机制: 工厂存在问题,循环中将创建新工厂
  • 核心: V value = suppile.get()
    public V get(K key, P parameter) {
        // lzy分析: null指针判断
        Objects.requireNonNull(parameter);
        // lzy分析: 将进入ReferenceQueue队列中数据,删除掉
        expungeStaleEntries();
        // lzy分析: 类加载器 和 引用队列,存储到WeakReference引用中
        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        // lzy分析: 通过类加载器,获取已加载过的接口和接口工厂
        // key: 类加载器的WeakReference封装
        // value: 
        //     key: 接口元数据
        //     value: 接口工厂(作用: 创建动态代理对象)
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        // lzy分析: 初始化操作,如果是第一次.那么创建一个空的Map
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        // lzy分析: 将所有接口进行hash唯一标识. 确保对应着一个工厂.
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        // lzy分析: 通过接口元数据对象,尝试性获取工厂
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            // lzy分析: 第一次是没有工厂的. 
            // 这一步在第一次会跳过 , 下面代码将创建工厂
            // 通常情况下,执行这一步.是在第二次循环.
            // 因为第一次循环,是在创建工厂
            // 只有到了第二次循环,工厂才被创建好.
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                // 利用工厂进行创建
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // lazily construct a Factory
            // 创建一个工厂
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }




            if (supplier == null) {
                // 将工厂放入缓存中
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    // 已经创建好了,为第二次循环作准备.
                    // 第二次循环,可以利用工厂进行创建
                    supplier = factory;
                }
                // else retry with winning supplier
                // lzy分析: 这是工厂的重试机制
                // 触发条件: V value = supplier.get();
                // 通过工厂创建对象,是null值
            } else {
                // lzy分析: 由于旧工厂存在问题,无法成功创建对
                // 那么使用新工厂来代替旧工厂.
                // 意味着: 将进入下一轮循环.用新工厂,创建对象.
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

源码细节分析: CacheKey.valueOf(key,refQueue)

  • 作用:弱引用,GC触发时一定会被回收.但WeakReference对象本身,将进入到ReferenceQueue中
    private static final class CacheKey<K> extends WeakReference<K> {
            static <K> Object valueOf(K key, ReferenceQueue<K> refQueue) {
            return key == null
                   // null key means we can't weakly reference it,
                   // so we use a NULL_KEY singleton as cache key
                   ? NULL_KEY
                   // non-null key requires wrapping with a WeakReference
                   : new CacheKey<>(key, refQueue);
        }
    }

源码细节分析: WeakCache.expungeStaleEntries()

  • 作用: 每次创建动态代理时,都会先清理一遍因GC触发而保留下来的Reference中引用.
    private void expungeStaleEntries() {
        CacheKey<K> cacheKey;
        while ((cacheKey = (CacheKey<K>)refQueue.poll()) != null) {
            cacheKey.expungeFrom(map, reverseMap);
        }
    }

源码细节分析: Proxy.KeyFactory.apply()

  • 作用: 将所有接口进行hash值.确保唯一标识,对应着一个工厂
  • 位置: subkeyFactory.apply(key,parameter)
    private static final class KeyFactory
        implements BiFunction<ClassLoader, Class<?>[], Object>
{
        
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值