JDK 动态代理实现及原理解析

前面介绍了代理模式 ,讲了动态代理常见的实现方式,包含了JDK的动态代理和CGLib的动态代理。本文将介绍下JDK 动态代理实现及机制。

首先,要了解的是InvocationHandler接口。

"InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler."

InvocationHandler是每个完成方法调用处理的代理实例需要实现的接口。每个代理实例都有关联的一个调用处理者。当一个方法被代理实例执行时,方法调用会被转发到调用处理者执行。

这个接口有一个方法:

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

其中proxy是生成代理的对象,method是方法,args是方法参数。来看下具体用法:

/**
 * Create by zxb on 2017/4/23
 */
public interface IDBQuery {
    String getElement(String id);
}

/**
 * Create by zxb on 2017/4/23
 */
public class DBQuery implements IDBQuery {

    public String getElement(String id) {
        return id + "_JDKProxy";
    }
}

/**
 * Create by zxb on 2017/4/23
 */
public class DBQueryProxy implements InvocationHandler {

    private DBQuery dbQuery;

    public DBQueryProxy(DBQuery dbQuery) {
        this.dbQuery = dbQuery;
    }

    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        return method.invoke(dbQuery, objects);
    }
}

/**
 * Create by zxb on 2017/4/23
 */
public class TestJDKProxy {

    public static void main(String[] args) {
        DBQuery dbQuery = new DBQuery();
        DBQueryProxy dbQueryProxy = new DBQueryProxy(dbQuery);
        IDBQuery query = (IDBQuery) Proxy
                .newProxyInstance(dbQuery.getClass().getClassLoader(), dbQuery.getClass().getInterfaces(),
                        dbQueryProxy);
        System.out.println(query.getElement("Hello"));
    }
}

执行结果:

JDK 动态代理实现及原理解析_第1张图片


其中需要注意的是,实现了InvocationHandler接口的DBQueryProxy,依赖真实对象。开始的时候,对这个不解,但是后来有了了解,才知道是需要这么写的。如果使用method.invoke(o,args)那么就会变成死循环,不断调自己。后面有解释。

所以看完例子,这里最重要的就是

Proxy.newProxyInstance(dbQuery.getClass().getClassLoader(), dbQuery.getClass().getInterfaces(), dbQueryProxy);
看下newProxyInstance的实现

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

        /*
         * 查找 or 生成 指定的代理类,这步有用到缓存
         */
        Class cl = getProxyClass0(loader, intfs);

        /*
         * 通过指定的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;
                    }
                });
            }
            //生成实例
            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);
        }
    }
通过getProxyClass0方法来获取代理类,

    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);
    }
其中proxyClassCache的定义为

   private static final WeakCache[], Class>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());  

这个WeakCache可以根据传入的ClassLoader、Class[] 接口类数组得到对应的key和代理的类,有点类似map。所以重点看ProxyClassFactory。

private static final class ProxyClassFactory
        implements BiFunction[], Class>
    {
        // 所有生成的代理类的前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // 下一个代理类的唯一标识值
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class apply(ClassLoader loader, Class[] interfaces) {
            //校验传入的接口数组,是否由loader加载的?是否是接口?是否重复?
            Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                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");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }
            
            String proxyPkg = null;     // 定义代理存放的包
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * 处理非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) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                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) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

OK,可以看到,关键是在

ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
来看ProxyGenerator的generateProxyClass方法传入代理类名称、接口、访问控制标志

public static byte[] generateProxyClass(final String var0, Class[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        //这步生成对应代理类的byte数组
        final byte[] var4 = var3.generateClassFile();
        //saveGeneratedFiles的值,由sun.misc.ProxyGenerator.saveGeneratedFiles变量值决定
        //保存生成的文件,否则直接返回byte数组
      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), new String[0]);
                            Files.createDirectories(var3, new FileAttribute[0]);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class", new String[0]);
                        }

                        Files.write(var2, var4, new OpenOption[0]);
                        return null;
                    } catch (IOException var4x) {
                        throw new InternalError("I/O exception saving generated file: " + var4x);
                    }
                }
            });
        }

        return var4;
    }
我们来看下,如何生成代理类byte数组
private byte[] generateClassFile() {
        添加hascode,equals,toString()方法
        this.addProxyMethod(hashCodeMethod, Object.class);
        this.addProxyMethod(equalsMethod, Object.class);
        this.addProxyMethod(toStringMethod, Object.class);
        Class[] var1 = this.interfaces;
        int var2 = var1.length;

        int var3;
        Class var4;
        //遍历接口,添加方法
       for(var3 = 0; var3 < var2; ++var3) {
            var4 = var1[var3];
            Method[] var5 = var4.getMethods();
            int var6 = var5.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                Method var8 = var5[var7];
                this.addProxyMethod(var8, var4);
            }
        }

        Iterator var11 = this.proxyMethods.values().iterator();

        List var12;
        while(var11.hasNext()) {
            var12 = (List)var11.next();
            checkReturnTypes(var12);
        }

        Iterator var15;
        try {
            //添加构造函数
           this.methods.add(this.generateConstructor());
            var11 = this.proxyMethods.values().iterator();

            while(var11.hasNext()) {
                var12 = (List)var11.next();
                var15 = var12.iterator();
                //添加方法及字段
                while(var15.hasNext()) {
                    ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
                    this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                    this.methods.add(var16.generateMethod());
                }
            }
            //添加静态初始化语句
            this.methods.add(this.generateStaticInitializer());
        } catch (IOException var10) {
            throw new InternalError("unexpected I/O Exception", var10);
        }

        if(this.methods.size() > '\uffff') {
            throw new IllegalArgumentException("method limit exceeded");
        } else if(this.fields.size() > '\uffff') {
            throw new IllegalArgumentException("field limit exceeded");
        } else {
            this.cp.getClass(dotToSlash(this.className));
            this.cp.getClass("java/lang/reflect/Proxy");
            var1 = this.interfaces;
            var2 = var1.length;

            for(var3 = 0; var3 < var2; ++var3) {
                var4 = var1[var3];
                this.cp.getClass(dotToSlash(var4.getName()));
            }

            this.cp.setReadOnly();
            ByteArrayOutputStream var13 = new ByteArrayOutputStream();
            DataOutputStream var14 = new DataOutputStream(var13);

            try {
                var14.writeInt(-889275714);
                var14.writeShort(0);
                var14.writeShort(49);
                this.cp.write(var14);
                var14.writeShort(this.accessFlags);
                var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
                var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
                var14.writeShort(this.interfaces.length);
                Class[] var17 = this.interfaces;
                int var18 = var17.length;

                for(int var19 = 0; var19 < var18; ++var19) {
                    Class var22 = var17[var19];
                    var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
                }

                var14.writeShort(this.fields.size());
                var15 = this.fields.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                    var20.write(var14);
                }

                var14.writeShort(this.methods.size());
                var15 = this.methods.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                    var21.write(var14);
                }

                var14.writeShort(0);
                return var13.toByteArray();
            } catch (IOException var9) {
                throw new InternalError("unexpected I/O Exception", var9);
            }
        }
    }

在前面的Test类中,添加

System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

重新执行,可以在项目的根目录中多了com文件夹,点进去可以在 com\sun\proxy\目录下找到$Proxy0.class文件,这个就是生成的代理类的字节码。反编译出来看下

package com.sun.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import org.zheng.proxy.jdk.IDBQuery;

public final class $Proxy0 extends Proxy
  implements IDBQuery
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m0;

  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final String getElement(String paramString)
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m3, new Object[] { paramString });
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("org.zheng.proxy.jdk.IDBQuery").getMethod("getElement", new Class[] { Class.forName("java.lang.String") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", 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());
  }
}

可以看到:

1)$Proxy0继承了Proxy实现了IDBQuery接口。

2)getElement方法,是this.h.invoke(this, m3, new Object[] { paramString }); 这就是调用我们DBQueryProxy的invoke方法,传入代理类本身的实例,试想,如果还是用method.invoke(o,args)那么就一直是跳入代理类执行了。

3)这个代理类本身是没有真实对象的,所以必须要依赖于外部传入的对象来执行方法。所以在DBQueryProxy需要依赖真实对象,就是这么回事。


好的,理清楚了,下篇写CGLib动态代理的。

你可能感兴趣的:(Java工具类)