Java-反射-动态代理

概述

  • Proxy 提供静态方法来创建动态代理类和动态代理对象;
  • 源码基于 Android-SDK-29 中的 JDK;

动态代理类

  • 动态代理类的父类是 Proxy,并且实现了动态创建时指定的接口;类名不是明确的,以 $Proxy 开头;
  • 如果代理接口都是 public ,那么动态代理类是 public final 的,不是 abstract;如果代理接口中有任意一个是 not public ,那么动态代理类是 not public final 的,不是 abstract ,动态代理类所在的包和 not public 代理接口所在的包一致;
  • 每个动态代理类有一个 public 的构造函数,该构造函数只有一个 InvocationHandler 类型的参数;
  • 如果一个具有相同排列的代理接口的动态代理类已经被一个 ClassLoader 定义了,就不会重复生成新的动态代理类

动态代理对象

  • 动态代理对象是动态代理类的实例,动态代理类的构造方法是只有一个 InvocationHandler 类型的参数;
  • 动态代理对象的所有方法调用,包括 hashCode equals toString ,以及代理接口的方法调用,都是转发给关联的 InvocationHandler 对象实现的;

源码

  • InvocationHandler
    protected InvocationHandler h;
    
    protected Proxy(InvocationHandler h) {
          Objects.requireNonNull(h);
          this.h = h;
      }
    
    public interface InvocationHandler {
    
      public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable;
    }
    
    • 每个动态代理对象都绑定一个 InvocationHandler 对象,动态代理对象的所有方法调用,都要转发给 InvocationHandler#invoke
  • getProxyClass
    private static Class<?> getProxyClass0(ClassLoader loader,
                                             Class<?>... interfaces) {
          if (interfaces.length > 65535) {
              throw new IllegalArgumentException("interface limit exceeded");
          }
          return proxyClassCache.get(loader, interfaces);
      }
    
    • 如果指定的 ClassLoader 已经定义了相同排列的代理接口的动态代理类,那么直接返回;否则,动态生成类;
  • newProxyInstance
    public static Object newProxyInstance(ClassLoader loader,
                                            Class<?>[] interfaces,
                                            InvocationHandler h)
          throws IllegalArgumentException
      {
          Objects.requireNonNull(h);
    
          final Class<?>[] intfs = interfaces.clone();
          //生成动态代理类
          Class<?> cl = getProxyClass0(loader, intfs);
    
          /*
           * Invoke its constructor with the designated invocation handler.
           */
          try {
              //动态代理类的构造函数
              final Constructor<?> cons = cl.getConstructor(constructorParams);
              final InvocationHandler ih = h;
              if (!Modifier.isPublic(cl.getModifiers())) {
                  cons.setAccessible(true);
              }
              //创建动态代理对象
              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);
          }
      }
    
    • 先生成对应的动态代理类,再通过构造函数生成动态代理对象;
  • isProxyClass
    public static boolean isProxyClass(Class<?> cl) {
          return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
      }
    
    • 判断是否是动态代理类;
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 自己备忘,随便写 android网络框架源码解析及对比 android常用网络框架对比 Volley: 特点 基于...
    幻海流心阅读 5,454评论 0 4
  • 使用Java反射,您可以在运行时创建接口的动态实现。 你可以使用类java.lang.reflect.Proxy。...
    FantJ阅读 4,342评论 0 1
  • 事例 小张是一个普普通通的码农,每天勤勤恳恳地码代码。某天中午小张刚要去吃饭,一个电话打到了他的手机上。“是XX公...
    余平的余_余平的平阅读 3,359评论 0 0
  • 就在这一瞬间,我对现在的生活产生了厌倦的情绪。于是我对L先生说:“我想去流浪,我想把我的生活过成小说里的样子。” ...
    素白林阅读 5,678评论 62 49
  • 如果,我是说如果 如果我做了那些事情, 世界该有怎样的变化。 如果我摘下夏天的叶子, 就没有秋天和冬天。 如果我绑...
    尼采海德格尔阅读 1,270评论 0 6

友情链接更多精彩内容