JAVA动态代理(proxy)源码分析

JDK动态代理(proxy)可以在运行时创建一个实现一组给定接口的新类。但是略有限制,即被代理的类必须实现某个接口,否则无法使用JDK自带的动态代理,因此,如果不满足条件,就只能使用另一种更加灵活,功能更加强大的动态代理技术—— CGLIB。Spring里会自动在JDK的代理和CGLIB之间切换,同时我们也可以强制Spring使用CGLIB。

下面先用实例介绍使用方式,接着从proxy类源码角度分析实现过程:

1.JDK动态代理实例

(1)动态代理首先提供一个调度处理器接口(Invocationhandler),该接口实例封装了我们要代理的对象实例的数据。 

 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Method;
 3 
 4 public class TranceHander implements InvocationHandler {
 5 
 6     private Object tObject;
 7 
 8     public TranceHander(Object t) {
 9         tObject = t;
10     }
11 
12     @Override
13     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
14         System.out.println("被代理对象:" + tObject);
15         System.out.println("方法:" + method.getName());
16         return method.invoke(tObject, args);// 方法反射
17     }
18 }

(2)使用Proxy类的newProxyInstance方法创建代理对象或getProxyClass方法获得代理类Class。

 

测试mian方法中,写了一个代理类,从1-1000的整数数组中使用二分查找随机查找一个整数,实现对象比较和toString接口代理

 

 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Proxy;
 3 import java.util.Arrays;
 4 
 5 import org.apache.commons.lang.math.RandomUtils;
 6 
 7 public class ProxyMain {
 8 
 9     public static void main(String[] args) {
10 
11         Object[] elements = new Object[1000];
12         for (int i = 0; i < elements.length; i++) {
13             Integer value = i + 1;// 被代理对象
14             InvocationHandler handler = new TranceHander(value);// 构建调度处理器
15             Object proxy = Proxy.newProxyInstance(null, new Class[] { Comparable.class }, handler);
16             elements[i] = proxy;
17         }
18 
19         Integer key = RandomUtils.nextInt(1000)+1;
20         int res = Arrays.binarySearch(elements, key);
21         if (res >= 0) {
22             System.out.println(elements[res].toString());
23         }
24         System.out.println("查找Key:" + key);
25     }
26 }

运行结果(每次结果不一样): 

被代理对象:500
方法:compareTo
被代理对象:250
方法:compareTo
被代理对象:125
方法:compareTo
被代理对象:187
方法:compareTo
被代理对象:156
方法:compareTo
被代理对象:140
方法:compareTo
被代理对象:148
方法:compareTo
被代理对象:152
方法:compareTo
被代理对象:152
方法:toString
152
查找Key:152

 

2.JDK源码实现原理分析

到这里我们发现,我们使用代理对象调用接口时候均调用TranceHander对象的invoker方法,使用Method的类的反射机制执行被代理对象的实现接口方法。 到这里我们得思考: 1. 这个代理对象是由谁且怎么生成的?

2. invoke方法是怎么调用的?

3. invoke和add方法有什么对应关系?

4. 生成的代理对象是什么样子的?    (1)代理对象生成:

Object proxy=Proxy.newProxyInstance(null, new Class[]{Comparable.class}, handler);  

(2)查看Proxy类的newProxyInstance方法

从生成对象方法中,我们看到三个关键的地方:

Class<?> cl = getProxyClass0(loader, interfaces);//得到代理类
final Constructor<?> cons = cl.getConstructor(constructorParams);   
newInstance(cons, ih);//将InvocationHandler h传入代理对象中
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);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        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;
                    }
                });
            }
            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);
        }
    }

(3)生成Proxy类,查看getProxyClass0方法,

 1     private static Class<?> getProxyClass0(ClassLoader loader,
 2                                            Class<?>... interfaces) {
 3         if (interfaces.length > 65535) {
 4             throw new IllegalArgumentException("interface limit exceeded");
 5         }
 6 
 7         // If the proxy class defined by the given loader implementing
 8         // the given interfaces exists, this will simply return the cached copy;
 9         // otherwise, it will create the proxy class via the ProxyClassFactory
10         return proxyClassCache.get(loader, interfaces);
11     }

其中proxyClassCache定义如下

《JAVA动态代理(proxy)源码分析》

查看ProxyClassFactory的定义

  1 /**
  2      * A factory function that generates, defines and returns the proxy class given
  3      * the ClassLoader and array of interfaces.
  4      */
  5     private static final class ProxyClassFactory
  6         implements BiFunction<ClassLoader, Class<?>[], Class<?>>
  7     {
  8         // prefix for all proxy class names
  9         private static final String proxyClassNamePrefix = "$Proxy";
 10 
 11         // next number to use for generation of unique proxy class names
 12         private static final AtomicLong nextUniqueNumber = new AtomicLong();
 13 
 14         @Override
 15         public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
 16 
 17             Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
 18             for (Class<?> intf : interfaces) {
 19                 /*
 20                  * Verify that the class loader resolves the name of this
 21                  * interface to the same Class object.
 22                  */
 23                 Class<?> interfaceClass = null;
 24                 try {
 25                     interfaceClass = Class.forName(intf.getName(), false, loader);
 26                 } catch (ClassNotFoundException e) {
 27                 }
 28                 if (interfaceClass != intf) {
 29                     throw new IllegalArgumentException(
 30                         intf + " is not visible from class loader");
 31                 }
 32                 /*
 33                  * Verify that the Class object actually represents an
 34                  * interface.
 35                  */
 36                 if (!interfaceClass.isInterface()) {
 37                     throw new IllegalArgumentException(
 38                         interfaceClass.getName() + " is not an interface");
 39                 }
 40                 /*
 41                  * Verify that this interface is not a duplicate.
 42                  */
 43                 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
 44                     throw new IllegalArgumentException(
 45                         "repeated interface: " + interfaceClass.getName());
 46                 }
 47             }
 48 
 49             String proxyPkg = null;     // package to define proxy class in
 50             int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
 51 
 52             /*
 53              * Record the package of a non-public proxy interface so that the
 54              * proxy class will be defined in the same package.  Verify that
 55              * all non-public proxy interfaces are in the same package.
 56              */
 57             for (Class<?> intf : interfaces) {
 58                 int flags = intf.getModifiers();
 59                 if (!Modifier.isPublic(flags)) {
 60                     accessFlags = Modifier.FINAL;
 61                     String name = intf.getName();
 62                     int n = name.lastIndexOf('.');
 63                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
 64                     if (proxyPkg == null) {
 65                         proxyPkg = pkg;
 66                     } else if (!pkg.equals(proxyPkg)) {
 67                         throw new IllegalArgumentException("non-public interfaces from different packages");
 69                     }
 70                 }
 71             }
 72 
 73             if (proxyPkg == null) {
 74                 // if no non-public proxy interfaces, use com.sun.proxy package
 75                 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
 76             }
 77 
 78             /*
 79              * Choose a name for the proxy class to generate.
 80              */
 81             long num = nextUniqueNumber.getAndIncrement();
 82             String proxyName = proxyPkg + proxyClassNamePrefix + num;
 83 
 84             /*
 85              * Generate the specified proxy class.
 86              */
 87             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
 89             try {
 90                 return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
 92             } catch (ClassFormatError e) {
 93                 /*
 94                  * A ClassFormatError here means that (barring bugs in the
 95                  * proxy class generation code) there was some other
 96                  * invalid aspect of the arguments supplied to the proxy
 97                  * class creation (such as virtual machine limitations
 98                  * exceeded).
 99                  */
100                 throw new IllegalArgumentException(e.toString());
101             }
102         }
103     }

这个方法实现了三个功能,

1: 18-47行抽取被代理类实现的接口Interface,检测是否符合要求
2: 49-82行根据接口的包名生成要存方的proxy的包名, 先定义代理类的包名,如果所有的接口都是公共的,则默认将创建的类放在String PROXY_PACKAGE = “com.sun.proxy”;中,若果存在
非public接口则所有的非public接口必须在同一包下,代理类也放在此包下,否则系统抛异常。
3. 最后创建类的字节码数组,读取并生成class

  (4)创建代理实例, 

cons.newInstance(new Object[]{h});//将类型为InvocationHandler的h传入代理对象中

 

其中,最重要的就是生成字节码的,直接调用的ProxyGenerator.generateProxyClass(proxyName, interfaces)接口生成的字节码

 1 import java.io.FileOutputStream;
 2 import java.io.IOException;
 3 
 4 import sun.misc.ProxyGenerator;
 5 
 6 public class CreateProxyTest {
 7     public static void main(String[] args) throws IOException {
 8          String path = "D://$Proxy0.class";
 9         byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", Integer.class.getInterfaces());
10 
11         FileOutputStream out = null;
12 
13         try {
14             out = new FileOutputStream(path);
15             out.write(classFile);
16             out.flush();
17         } catch (Exception e) {
18             e.printStackTrace();
19         } finally {
20             out.close();
21         }
22     }
23 }

接着将class文件反编译一下,反编译软件下载,直接用的Method的反射机制实现的代理,equal、hascode、toString方法是所有类都有的,compareTo则是被代理对象的实现接口: 

生成的 class 实现了compareTo并继承 Proxy ,所以生成代理只能用接口,因为java支持多继承

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

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

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

  public final boolean equals()
    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 int compareTo()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m3, new Object[] { paramObject })).intValue();
    }
    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("java.lang.Comparable").getMethod("compareTo", new Class[] { Class.forName("java.lang.Object") });
      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());
    }
  }
}

 

    原文作者:南极山
    原文地址: http://www.cnblogs.com/benwu/articles/8283549.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞