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定义如下
查看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()); } } }