JDK 动态代理实现及原理解析
来源:互联网 发布:js改变display属性 编辑:程序博客网 时间:2024/06/13 03:32
前面介绍了代理模式,讲了动态代理常见的实现方式,包含了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")); }}
执行结果:
其中需要注意的是,实现了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<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); } }通过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<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
这个WeakCache可以根据传入的ClassLoader、Class<?>[] 接口类数组得到对应的key和代理的类,有点类似map。所以重点看ProxyClassFactory。
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // 所有生成的代理类的前缀 private static final String proxyClassNamePrefix = "$Proxy"; // 下一个代理类的唯一标识值 private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { //校验传入的接口数组,是否由loader加载的?是否是接口?是否重复? Map<Class<?>, 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动态代理的。
- JDK 动态代理实现及原理解析
- JDK动态代理实现原理解析
- JDK动态代理原理及实现
- JDK动态代理实现及原理分析
- JDK动态代理的实现及原理
- JDK动态代理的实现及原理
- JDK动态代理的实现及原理
- JDK动态代理的实现及原理
- JDK动态代理的实现及原理
- JDK动态代理实现原理
- JDK动态代理实现原理
- JDK动态代理实现原理
- JDK动态代理实现原理
- jdk动态代理实现原理
- JDK动态代理实现原理
- JDK动态代理实现原理
- JDK动态代理实现原理
- JDK动态代理实现原理
- 李开复:创造伟大AI公司,要生逢其时,还要有正确的人
- 软工文档——总结
- SQLite数据库--案例:商品展示
- HAUTOJ-1267 ch追妹
- Android7.0 编译系统流程分析
- JDK 动态代理实现及原理解析
- centons7 mysql 安装及注意细节
- 翻转二叉树
- 一个MySql Sql 优化技巧分享
- C#中yield return用法分析
- java惰性初始化
- 文章标题
- jQuery闭包函数
- 使用D3制作统计图表、线性图表、水平柱状图表、饼图 -- (四)水平柱状图表+坐标轴