Java-API简析_java.lang.reflect.Proxy类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
https://blog.csdn.net/m0_69908381/article/details/131365827
出自【进步*于辰的博客

注:依赖类:Class

1、概述

继承关系:

  • java.lang.Object
    • java.lang.reflect.Proxy

所有已实现的接口:
Serializable


public class Proxy extends Object implements Serializable

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

创建某一接口 Foo 的代理:

InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(
    Foo.class.getClassLoader(), new Class[] { Foo.class });
Foo f = (Foo) proxyClass.
    getConstructor(new Class[] { InvocationHandler.class }).
    newInstance(new Object[] { handler });

或使用以下更简单的方法:

Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                     new Class[] { Foo.class },
                                     handler);

动态代理 \color{green}{动态代理} 动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 \color{blue}{ 代理接口} 代理接口是代理类实现的一个接口。 代理实例 \color{purple}{代理实例} 代理实例是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序对象,它可以实现接口 InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke(),并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。

代理类具用以下属性:

  • 代理类是公共的(public)、最终的(final),而不是抽象的(abstract)。
  • 未指定代理类的非限定名称。但是,以字符串 “$Proxy” 开头的类名空间应该为代理类保留。
  • 代理类扩展 java.lang.reflect.Proxy
  • 代理类会按同一顺序准确地实现其创建时指定的接口。
  • 如果代理类实现了非公共接口,那么它将在与该接口相同的包中定义。否则,代理类的包也是未指定的。注意,包密封将不阻止代理类在运行时在特定包中的成功定义,也不会阻止相同类加载器和带有特定签名的包所定义的类。
  • 由于代理类将实现所有在其创建时指定的接口,所以对其 Class 对象调用 getInterfaces() 将返回一个包含相同接口列表的数组(按其创建时指定的顺序),对其 Class 对象调用 getMethods() 将返回一个包括这些接口中所有方法的 Method 对象的数组,并且调用 getMethod() 将会在代理接口中找到期望的一些方法。
  • 如果 Proxy.isProxyClass() 传递代理类(由 Proxy.getProxyClass() 返回的类,或由 Proxy.newProxyInstance() 返回的对象的类),则该方法返回 true,否则返回 false。
  • 代理类的 java.security.ProtectionDomain 与由引导类加载器(如 java.lang.Object)加载的系统类相同,原因是代理类的代码由受信任的系统代码生成。此保护域通常被授予 java.security.AllPermission
  • 每个代理类都有一个可以带一个参数(接口 InvocationHandler 的实现)的公共构造方法,用于设置代理实例的调用处理程序。并非必须使用反射 API 才能访问公共构造方法,通过调用 Proxy.newInstance (将调用 Proxy.getProxyClass() 的操作和调用带有调用处理程序的构造方法结合在一起)也可以创建代理实例。

代理实例具有以下属性:

  • 提供代理实例 proxy 和一个由其代理类 Foo 实现的接口,以下表达式将返回 true:
proxy instanceof Foo

并且以下的强制转换操作将会成功(而不抛出 ClassCastException):

(Foo) proxy
  • 每个代理实例都有一个关联的调用处理程序,它会被传递到其构造方法中。静态 Proxy.getInvocationHandler() 将返回与作为其参数传递的代理实例相关的调用处理程序。
  • 代理实例上的接口方法调用将按照该方法的文档描述进行编码,并被指派到调用处理程序的 Invoke()
  • 在代理实例上的 java.lang.Object 中声明的 hashCode()equals()toString() 的调用将按照与编码和指派接口方法调用相同的方式进行编码,并被指派到调用处理程序的 invoke() ,如上所述。传递到 invoke() 的 Method 对象的声明类是 java.lang.Object。代理类不重写从 java.lang.Object 继承的代理实例的其他公共方法,所以这些方法的调用行为与其对 java.lang.Object 实例的操作一样。

在多代理接口中重复的方法

当代理类的两个或多个接口包含一个具有相同名称和参数签名的方法时,代理类的接口顺序变得非常重要。在代理实例上调用重复方法时,传递到调用处理程序的 Method 对象没有必要成为其声明类可以从接口(通过该接口调用代理方法)的引用类型指派的对象。此限制存在的原因是,生成的代理类中的相应方法实现无法确定它通过哪一个接口调用。因此,在代理实例上调用重复方法时,第一个接口中的方法的 Method 对象包含接口的代理类列表中的方法(直接或通过超级接口继承),该对象会传递到调用处理程序的 invoke() ,无论该方法调用通过哪一种引用类型发生。

如果代理接口包含某一方法,它的名称和参数签名与 java.lang.ObjecthashCode()equals()toString() 相同,那么在代理实例上调用这样的方法时,传递到调用处理程序的 Method 对象将使 java.lang.Object 成为其声明类。换句话说,java.lang.Object 公共的非最终方法理论上在所有代理接口之前,以便确定哪一个 Method 对象传递到调用处理程序。

还要注意,当重复方法被指派到调用处理程序时,invoke() 只可以抛出经过检查的异常类型,该异常类型可以使用所有代理接口(可以通过它调用)中方法的 throws 子句指派一种异常类型。如果 invoke() 抛出一个经过检查的异常,该异常没有指派给任何由一个代理接口(可以通过它调用)中的方法声明的异常类型,那么该代理实例上的调用将抛出一个未经检查的 UndeclaredThrowableException。此限制表示并非所有的由传递到 invoke() 的 Method 对象上调用 getExceptionTypes() 返回的异常类型都可以由 invoke() 成功抛出。

从以下版本开始:
1.3
另请参见:
InvocationHandler序列化表格

2、构造方法摘要

2.1 protected (InvocationHandler h)

根据指定的 InvocationHandler 构造 Proxy 对象。
说明:
先看源码。
在这里插入图片描述
后续解析。

3、方法摘要

3.1 static Class<?> getProxyClass(ClassLoader loader, Class<?>… interfaces)

返回代理类的 Class 对象。

public static Class<?> getProxyClass(ClassLoader loader,
                                     Class<?>... interfaces)
    throws IllegalArgumentException
{
    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    return getProxyClass0(loader, intfs);
}

后续解析。

3.2 static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

返回代理对象。

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    Objects.requireNonNull(h);

    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
     * Look up or generate the designated proxy class.
     */
    Class<?> cl = getProxyClass0(loader, intfs);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }

        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;
                }
            });
        }
        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);
    }
}

JDK动态代理就是通过此方法创建代理对象(如下),源码比较复杂,后续解析。

class Test {
    interface IService {}
    public static void main(String[] args) throws Exception {
        class Target implements IService {}
        Target target = new Target();
        IService proxy = (IService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object result = method.invoke(target, args);
                        return result;
                    }
                });
        System.out.println(proxy);// Test$1Target@5674cd4d
    }
}

3.3 static boolean isProxyClass(Class<?> cl)

判断指定的 Class 对象是否表示代理类。

public static boolean isProxyClass(Class<?> cl) {
    return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
}

关于isAssignableFrom(),见 Class 类的第2.48项;关于proxyClassCache,暂未知,后续补充解析。

3.4 static InvocationHandler getInvocationHandler(Object 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;
    if (System.getSecurityManager() != null) {
        Class<?> ihClass = ih.getClass();
        Class<?> caller = Reflection.getCallerClass();
        if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(),
                                                ihClass.getClassLoader()))
        {
            ReflectUtil.checkPackageAccess(ihClass);
        }
    }

    return ih;
}

后续解析。

4、方法摘要(不开放)

4.1 private static void checkProxyAccess(Class<?> caller, ClassLoader loader, Class<?>… interfaces)

检查代理权限。

private static void checkProxyAccess(Class<?> caller,
                                     ClassLoader loader,
                                     Class<?>... interfaces)
{
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        ClassLoader ccl = caller.getClassLoader();
        if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
            sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
        }
        ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
    }
}

后续解析。

4.2 private static Class<?> getProxyClass0(ClassLoader loader, Class<?>… interfaces)

返回代理类的 Class 对象。

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);
}

后续解析。

4.3 private static void checkNewProxyPermission(Class<?> caller, Class<?> proxyClass)

检查构造的代理对象权限。

private static void checkNewProxyPermission(Class<?> caller, Class<?> proxyClass) {
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        if (ReflectUtil.isNonPublicProxyClass(proxyClass)) {
            ClassLoader ccl = caller.getClassLoader();
            ClassLoader pcl = proxyClass.getClassLoader();

            // do permission check if the caller is in a different runtime package
            // of the proxy class
            int n = proxyClass.getName().lastIndexOf('.');
            String pkg = (n == -1) ? "" : proxyClass.getName().substring(0, n);

            n = caller.getName().lastIndexOf('.');
            String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);

            if (pcl != ccl || !pkg.equals(callerPkg)) {
                sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
            }
        }
    }
}

后续解析。

4.4 private static native Class<?> defineClass0(ClassLoader loader, String name, byte[] b, int off, int len)

根据指定的类加载器、类名等信息构造 Class 对象。

private static native Class<?> defineClass0(ClassLoader loader, String name,
                                                byte[] b, int off, int len);

后续解析。

最后

如果大家需要Java-API文档,我上传了《Java-API文档-包含5/8/11三个版本》。


本文暂缓更新。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进步·于辰

感谢打赏!很高兴可以帮到你!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值