首页 > 其他分享 >动态代理原理

动态代理原理

时间:2023-01-06 15:03:10浏览次数:40  
标签:interfaces 代理 private final new 原理 动态 Class

简介

java.lang.reflect.Proxy是整个jdk中实现动态代理的核心 类,本文主要介绍Proxy类的实现,关于Proxy类的使用请自行查阅其他资料。

Field

  • constructorParams:构造函数的参数,用于代理类的核心的逻辑实现,关于InvocationHandler这个接口的介绍不是本文的重点,此处不做介绍。

private static final Class<?>[] constructorParams =
  { InvocationHandler.class };
  • proxyClassCache: 代理类的缓存,此类是一个二级缓存的实现,利用WeakReference的特性,当内存占用过高的时候会JVM自动进行回收缓存中的数据。

private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
   proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
  • h: InvocationHandler接口,用于此代理实例的调用处理程序。

Inner Class

  • KeyFactory:顾名思义,缓存代理的key的工厂实现,此类仅一个方法,实现了BiFunction接口,具体代码如下

private static final class KeyFactory
   implements BiFunction<ClassLoader, Class<?>[], Object>
{
   @Override
   public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
       switch (interfaces.length) {
           case 1: return new Key1(interfaces[0]); // the most frequent
           case 2: return new Key2(interfaces[0], interfaces[1]);
           case 0: return key0;
           default: return new KeyX(interfaces);
      }
  }
}

由以上代码可见,该类的实现分为委托给了Key0,Key1,Key2,KeyX这四个类实现,其中key0是一个Object,其他的类Key1,Key2,KeyX则是分别用不同的实现对hashcode和equals方法进行了不同的实现,大同小异。这里则分别简单的做一下解释。

private static final class Key1 extends WeakReference<Class<?>> {
   private final int hash;

   Key1(Class<?> intf) {
       super(intf);
       this.hash = intf.hashCode();
  }

   @Override
   public int hashCode() {
       return hash;
  }

   @Override
   public boolean equals(Object obj) {
       Class<?> intf;
       return this == obj ||
              obj != null &&
              obj.getClass() == Key1.class &&
              (intf = get()) != null &&
              intf == ((Key1) obj).get();
  }
}
private static final class Key2 extends WeakReference<Class<?>> {
   private final int hash;
   private final WeakReference<Class<?>> ref2;

   Key2(Class<?> intf1, Class<?> intf2) {
       super(intf1);
       hash = 31 * intf1.hashCode() + intf2.hashCode();
       ref2 = new WeakReference<Class<?>>(intf2);
  }

   @Override
   public int hashCode() {
       return hash;
  }

   @Override
   public boolean equals(Object obj) {
       Class<?> intf1, intf2;
       return this == obj ||
              obj != null &&
              obj.getClass() == Key2.class &&
              (intf1 = get()) != null &&
              intf1 == ((Key2) obj).get() &&
              (intf2 = ref2.get()) != null &&
              intf2 == ((Key2) obj).ref2.get();
  }
}
private static final class KeyX {
   private final int hash;
   private final WeakReference<Class<?>>[] refs;

   @SuppressWarnings("unchecked")
   KeyX(Class<?>[] interfaces) {
       hash = Arrays.hashCode(interfaces);
       refs = (WeakReference<Class<?>>[])new WeakReference<?>[interfaces.length];
       for (int i = 0; i < interfaces.length; i++) {
           refs[i] = new WeakReference<>(interfaces[i]);
      }
  }

   @Override
   public int hashCode() {
       return hash;
  }

   @Override
   public boolean equals(Object obj) {
       return this == obj ||
              obj != null &&
              obj.getClass() == KeyX.class &&
              equals(refs, ((KeyX) obj).refs);
  }

   private static boolean equals(WeakReference<Class<?>>[] refs1,
                                 WeakReference<Class<?>>[] refs2) {
       if (refs1.length != refs2.length) {
           return false;
      }
       for (int i = 0; i < refs1.length; i++) {
           Class<?> intf = refs1[i].get();
           if (intf == null || intf != refs2[i].get()) {
               return false;
          }
      }
       return true;
  }
}
  • ProxyClassFactory: 顾名思义, 代理类的生产工厂类,用于生成代理类,此类也是实现了BiFunction,技能一个apply方法,最终根据ClassLoader,Interface,proxyName参数调用java.lang.reflect.Proxy#defineClass0这个本地方法生成代理类。

private static final class ProxyClassFactory
   implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
   // 代理类名称的前缀,我们看到的代理类的名称都有这个前缀就是这个原因
   private static final String proxyClassNamePrefix = "$Proxy";

   // 用于生成代理类名称的唯一的序号
   private static final AtomicLong nextUniqueNumber = new AtomicLong();

   @Override
   public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

       Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
       for (Class<?> intf : interfaces) {
           /*
            * 验证类加载器是否将此接口的名称解析为同一类对象
            */
           Class<?> interfaceClass = null;
           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");
          }
           /*
            * 校验接口是不重复的
            */
           if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
               throw new IllegalArgumentException(
                   "repeated interface: " + interfaceClass.getName());
          }
      }
// 代理类包名
       String proxyPkg = null;  
       //代理类的访问修饰符
       int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

       /*
        * 记录非public的代理接口的包,以至于代理类的定义是相同的包,验证所有的非public的代理接口在相同的包中。
        */
       for (Class<?> intf : interfaces) {
           int flags = intf.getModifiers();
           if (!Modifier.isPublic(flags)) {
               accessFlags = Modifier.FINAL;
               String name = intf.getName();
               int n = name.lastIndexOf('.');
               String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
               if (proxyPkg == null) {
                   proxyPkg = pkg;
              } else if (!pkg.equals(proxyPkg)) {
                   throw new IllegalArgumentException(
                       "non-public interfaces from different packages");
              }
          }
      }

       if (proxyPkg == null) {
           //如果没有非public的代理接口,则用com.sun.proxy这个包
           proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
      }

       /*
        * 为生成的代理类选择一个名称
        */
       long num = nextUniqueNumber.getAndIncrement();
       //代理类名称
       String proxyName = proxyPkg + proxyClassNamePrefix + num;

       /*
        * 生成代理类
        */
       byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
           proxyName, interfaces, accessFlags);
       try {
           return defineClass0(loader, proxyName,
                               proxyClassFile, 0, proxyClassFile.length);
      } catch (ClassFormatError e) {
           /*
            * 如果出现了ClassFormatError则意味着提供给代理类创建的参数还有其他一些无效方面或者生成代理的代码有bug。(例如超出虚拟机限制)
            */
           throw new IllegalArgumentException(e.toString());
      }
  }
}

/**
*生成代理类的本地方法
*/
private static native Class<?> defineClass0(ClassLoader loader, String name,
                                               byte[] b, int off, int len);

核心方法

  • newProxyInstance: 返回一个指定接口的代理类的实例,将该代理类调度到指定的处理方法。

    arguments:

    • ClassLoader:生成代理类的类加载器

    • Class<?>[]: 被代理的类实现的接口

    • InvocationHandler: 处理被代理类的方法,每一个被代理的类都将由指定的InvocationHandler处理。

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

       /*
        * 根据类加载器和代理类实现的接口查找或者生成代理类
        */
       Class<?> cl = getProxyClass0(loader, intfs);

       try {
           if (sm != null) {
               checkNewProxyPermission(Reflection.getCallerClass(), cl);
          }
    //获取构造函数
           final Constructor<?> cons = cl.getConstructor(constructorParams);
           //处理程序
           final InvocationHandler ih = h;
           //访问修饰符不是public则利用AccessController做权限控制,设置可访问
           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);
      }
    }

疑问

至此,代理类的实例已经创建完成,但是我们仍可能有以下几个疑问

  • 1:代理类defineClass0方法是如何生成的?

  • 2:如何使用代理类?

  • 3:getProxyClass0是如何创建实例的?

我们带着以上几个疑问深入深入探讨一下其中的原理。

1:代理类defineClass0方法是如何生成的?这个问题已经超纲了,仅能结合已有的只是浅显的说一下(好像又没说)。我们都知道Java是通过虚拟机编译.java文件生成.class文件,而defineClass0方法就是通过模拟JVM编译Java文件的过程生成class文件的过程,这个过程包括编译原理,虚拟机的一些底层原理,已经不再本文的探讨范文之内了,也希望有了解的朋友科普一下,在此表示感谢!

2:如何使用代理类,我们在使用newProxyInstance方法创建代理类的时候传入了一个InvocationHandler参数,这个接口里面有一个方法就是用来处理代理类的方法的,该类仅有一个invoke方法,可以通过反射去调用代理了的原有的逻辑,并在处理原有的逻辑的基础上增加一些额外的逻辑,方法原型如下。

public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable;

3:getProxyClass0是如何创建实例的,此方法没有什么特别的逻辑,仅做了一下简单的校验,然后就调用了proxyClassCache的get方法或者代理类对象,是不是感觉上面的KeyFactory和ProxyClassFactory没有用到呢?这个时候我们就需要重新看一下Field里面的proxyClassCache初始化的时候传入了keyFactory和ProxyClassFactory具体的逻辑都在该类的get方法里面了。具体的实现逻辑请参照WeakCache,为了文章的专一性,本文就不再对WeakCache做介绍了,后面会有一篇专门的文章介绍WeakCache。

private static Class<?> getProxyClass0(ClassLoader loader,
                                      Class<?>... interfaces) {
   if (interfaces.length > 65535) {
       throw new IllegalArgumentException("interface limit exceeded");
  }
//假如代理类已经在被给的ClassLoader和代理类实现的接口已存在,那就简单的返回缓存的副本,否则的话,就通过ProxyClassFactory创建一个新的代理类
   return proxyClassCache.get(loader, interfaces);
}

结语

到此为止,我们已经把Proxy中如何创建代理类的过程和原理有了完整的了解,当然还一些不完整的地方和不恰当的地方希望热心的朋友指出和补充。

 

标签:interfaces,代理,private,final,new,原理,动态,Class
From: https://www.cnblogs.com/wkynf/p/17030472.html

相关文章

  • 22、Electron常见动态链错误
    1、UncaughtError:DynamicLinkingError:Win32error126DLL引用的路径错误,检查下DLL的路径是否正确 2、UncaughtError:DynamicLinkingError:Win32error193......
  • Java监听器实现原理
    文章目录​​监听器模型​​​​案例实现​​​​`DeveloperListener`​​​​`Developer`​​​​`Event`​​​​`DeveloperListenerImpl`​​​​测试​​监听器就是监听......
  • vue 配置代理
    如果接口请求存在跨域问题且后端暂没时间解决,可以通过vue-cli配置代理的方式解决:.env.development中设置VUE_APP_BASE_API=LocalLocal为该项目运行时的服务器地址,vue......
  • 写过vue自定义指令吗,原理是什么?.m
    背景看了一些自定义指令的文章,但是探究其原理的文章却不多见,所以我决定水一篇。如何自定义指令?其实关于这个问题官方文档上已经有了很好的示例的,我们先来温故一下。除......
  • opencv卡尺测量原理
    遍历每个矩形区域,分别找到一个灰度突变的峰值,然后把这N个点剔除问题点拟合直线或圆。可以通过卡尺检测边缘,再用投影法,再求灰度平均值沿着边缘检测方向,垂直扫描图像如图......
  • 动态对象跟踪 SLAM:DyOb-SLAM
    以下内容来自从零开始机器人SLAM知识星球每日更新内容点击领取学习资料→机器人SLAM学习资料大礼包论文#DyOb-SLAM:DynamicObjectTrackingSLAMSystem论文地址......
  • 通过DHCP动态管理IP地址
    DHCP动态主机配置协议是一个局域网的网络协议,使用UDP协议工作,主要有两个用途:给内部网络或网络服务供应商自动分配IP地址、子网掩码、网关以及DNS等tcp/ip信息,给用户或者......
  • 使用Squid部署代理服务
    Squid是Linux系统中最为流行的一款高性能代理服务软件,通常用作Web网站的前置缓存服务,能够代替用户向网站服务器请求页面数据并进行缓存.简单来说,Squid服务程序会按照收到......
  • elementui 动态table表头
    <el-tablesize="mini":stripe="false":header-cell-style="{'background':'#d3e0ff'}":row-class-name="rowClass":data="tableData"......
  • 正向代理和反向代理
    https://blog.csdn.net/Dax1_/article/details/124652162?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167291795416800184194599%2522%252C%2522scm%2522%2......