美文网首页
JAVA动态代理的实现原理

JAVA动态代理的实现原理

作者: lfg枫林 | 来源:发表于2021-02-18 20:11 被阅读0次

    java动态代理主要是有Proxy和InvocationHandler两个类实现的
    一、我先来看下如何使用Proxy和InvocationHandler来实现动态代理
    1.先定义一个接口MarkMan


    image.png
    1. 再定义的一个类MarkManFactory实现MarkMan


      image.png
    2. 然后定义一个MyInvocationHandler实现InvocationHandler。
      在里面定义一个setFactory(Object obj)方法把要代理的对象传入进去,然后定义个newProxyInstance方法,方法里面调用Proxy.newProxyInstance()方法获取代理对象。
      实现InvocationHandler的invoke方法


      image.png

      4.然后在main方法中进行调用


      image.png
      我们运行下程序,结果打压如下
      image.png
      二、通过调试模式我们发现,动态代理里,代理类的类名是这样的:
      [图片上传失败...(image-9e5ea5-1613977035476)]

      这个代理类为何是这个名字?它是如何执行被代理对象的相关方法呢?我们在java文件编译后的目录里其实找不到这个名为$Proxy0的class文件的。带着这个问题我来看看Proxy和InvocationHandler的源码 看它们是如何实现动态代理的
      查看Proxy的newProxyInstance方法源码

      @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
     InvocationHandler h)
            throws IllegalArgumentException {
            Objects.requireNonNull(h);
           ........
            /*
             * Look up or generate the designated proxy class.
             */
        //获取clazz对象
            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;
                        }
                    });
                }
              //通过构造函数new一个实例对象
                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);
            }
        }
    

    通过源码我们可以看到是newProxyInstance是通过获取class对象,然后通过class对象获取构造函数,通过构造函数new一个实例对象返回 接下来我们看下getProxyClass0(loader, intfs)方法

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

    通过源码 我们发现getProxyClass0就是从缓存中去获取,继续看WeakCache的get方法
    这里我们主要看下subKeyFactory.apply(key, parameter)方法 ,其余都是验证跟判断

      public V get(K key, P parameter) {
      ....省略
         Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
         Supplier<V> supplier = valuesMap.get(subKey);
         Factory factory = null;
         while (true) {
                if (supplier != null) {
                    V value = supplier.get();
                    if (value != null) {
                        return value;
                    }
                }
                if (factory == null) {
                    factory = new Factory(key, parameter, subKey, valuesMap);
                }
                if (supplier == null) {
                    supplier = valuesMap.putIfAbsent(subKey, factory);
                    if (supplier == null) {
                        supplier = factory;
                    }
                } else {
                    if (valuesMap.replace(subKey, supplier, factory)) {
                        supplier = factory;
                    } else {
                        // retry with current supplier
                        supplier = valuesMap.get(subKey);
                    }
                }
            }
      }
    

    subKeyFactory是BiFunction接口,通过查看实现类发现是ProxyClassFactory类,接下来看ProxyClassFactory 的apply方法

    public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
                ....省略
                String proxyPkg = null;     // package to define proxy class in
                int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
                long num = nextUniqueNumber.getAndIncrement();
               ** //代理类的名称  这里就是我们的要找的答案  $Proxy0 **
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                /*
                 * Generate the specified proxy class.
                 */
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
                try {
                    return defineClass0(loader, proxyName,
                                        proxyClassFile, 0, proxyClassFile.length);
                } catch (ClassFormatError e) {
                    throw new IllegalArgumentException(e.toString());
                }
            }
    

    通过源码我们发现通过ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags) 转换成byte[]数组,然后通过defineClass0方法转换成Class字节码返回,

     public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
            ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
            final byte[] var4 = var3.generateClassFile();
            if (saveGeneratedFiles) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        try {
                            int var1 = var0.lastIndexOf(46);
                            Path var2;
                            if (var1 > 0) {
                                Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
                                Files.createDirectories(var3);
                                var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                            } else {
                                var2 = Paths.get(var0 + ".class");
                            }
    
                            Files.write(var2, var4, new OpenOption[0]);
                            return null;
                        } catch (IOException var4x) {
                            throw new InternalError("I/O exception saving generated file: " + var4x);
                        }
                    }
                });
            }
    
            return var4;
        }
        //本地方法
        private static native Class<?> defineClass0(ClassLoader loader, String name,
                                                    byte[] b, int off, int len);
    

    为了查看byte[]数组里面的内容我们可以自己定义个ProxyUtils工具类把byte[]写到文件中,查看里面的内容

    public class ProxyUtils {
        public static void generateClassFile(Class clazz,String proxyName){
            /*ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);*/
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, new Class[]{clazz});
            String paths = clazz.getResource(".").getPath();
            System.out.println(paths);
            FileOutputStream out = null;
            try {
                out = new FileOutputStream(paths+proxyName+".class");
                out.write(proxyClassFile);
                out.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    运行代码 我看到生成的文件是以Proxy0、Proxy1这么的名称
    查看里面的内容

    public final class $Proxy0 extends Proxy implements Person
    {
      private static Method m1;
      private static Method m2;
      private static Method m3;
      private static Method m0;
      
      /**
      *注意这里是生成代理类的构造方法,方法参数为InvocationHandler类型,看到这,是不是就有点明白
      *为何代理对象调用方法都是执行InvocationHandler中的invoke方法,而InvocationHandler又持有一个
      *被代理对象的实例,不禁会想难道是....? 没错,就是你想的那样。
      *
      *super(paramInvocationHandler),是调用父类Proxy的构造方法。
      *父类持有:protected InvocationHandler h;
      *Proxy构造方法:
      *    protected Proxy(InvocationHandler h) {
      *         Objects.requireNonNull(h);
      *         this.h = h;
      *     }
      *
      */
      public $Proxy0(InvocationHandler paramInvocationHandler) throws {
        super(paramInvocationHandler);
      }
      
      //这个静态块本来是在最后的,我把它拿到前面来,方便描述
       static{
        try {
          //看看这儿静态块儿里面有什么,是不是找到了saleMan方法。请记住saleMan通过反射得到的名字m3,其他的先不管
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {       
          Class.forName("java.lang.Object") });
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
          m3 = Class.forName("proxy.MarkManFactory").getMethod("saleMan", new Class[0]);
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
          return;
        } catch (NoSuchMethodException localNoSuchMethodException){
          throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }catch (ClassNotFoundException localClassNotFoundException){
          throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
      }
    
      /**
      * 
      *这里调用代理对象的saleMan方法,直接就调用了InvocationHandler中的invoke方法,并把m3传了进去。
      *this.h.invoke(this, m3, null);这里简单,明了。
      *来,再想想,代理对象持有一个InvocationHandler对象,InvocationHandler对象持有一个被代理的对象,
      *再联系到InvacationHandler中的invoke方法。嗯,就是这样。
      */
      public final void saleMan() throws {
        try {
          this.h.invoke(this, m3, null);
          return;
        }catch (Error|RuntimeException localError){
          throw localError;
        }catch (Throwable localThrowable){
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
      //注意,这里为了节省篇幅,省去了toString,hashCode、equals方法的内容。原理和saleMan方法一毛一样。
    }
    

    这的h是什么呢 我们看下Proxy类可以看到


    image.png

    这个h的实例来自哪里?不就是我们在创建代理类的实例时传入的吗?


    image.png
    到此整个动态代理的源码分析就结束了

    相关文章

      网友评论

          本文标题:JAVA动态代理的实现原理

          本文链接:https://www.haomeiwen.com/subject/ybenxltx.html