JAVA动态代理的实现原理

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

运行代码 我看到生成的文件是以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动态代理的实现原理)