JDK动态代理之实现与原理(二)【JDK篇】

// 创建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方法中回调用真实对象的相应方法。

原文 

https://juejin.im/post/5f0718a5e51d453483427775

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » JDK动态代理之实现与原理(二)【JDK篇】

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址