设计模式--JDK动态代理的实现与原理解析(2)
来源:互联网 发布:怎么样做淘宝客赚钱 编辑:程序博客网 时间:2024/06/06 18:36
在上一篇博客中,实现了JDK的动态代理。但是,我们不仅要学会如何使用,更要理解其内部的具体实现。
我们是通过此方法获得对目标对象的代理类:
public Object getProxy() { //参数意义:1. 当前类加载器 2. 目标类的class对象 3. 目标类的所有接口 4. 实现InvocationHandler接口的类 return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this); }
接下来,进入newProxyInstance()中看一下其实现逻辑(JDK1.8的实现):具体的解释都在代码中体现
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { //Objects提供了操作Object类的一些实用方法。判断h不为空,为空抛出空指针异常 Objects.requireNonNull(h); // 复制接口的class对象 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对象。 */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } // 获得代理类的构造函数,参数constructorParams //private static final Class<?>[] constructorParams ={ InvocationHandler.class }; 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; } }); } //利用构造函数,创建代理类实例,参数是自己实现了InvocationHandler的代理逻辑类 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); } }
上边的源码中其实核心点就是我注释的那几行。其中生成代理类的class对象的方法为:
Class<?> cl = getProxyClass0(loader, intfs);
进入此方法中看一下:
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { //当被代理的目标类的接口大于65535,则抛出异常。---估计没人会写这种代码吧 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); }
这个方法是获得代理类对象的关键。
return proxyClassCache.get(loader, interfaces);
通过上边的注释,就可知道,对代理类进行了缓存,当查找缓存中没有时,就会通过ProxyClassFactory来创建代理类。可以查看proxyClassCache变量的定义:
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
从定义上可以看到,它是通过WeakCache来实现缓存的。WeakCache Java的弱引用。
public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) { this.subKeyFactory = Objects.requireNonNull(subKeyFactory); this.valueFactory = Objects.requireNonNull(valueFactory); }
构造函数,传入两个类对象:new KeyFactory()和new ProxyClassFactory()。这两个类都是Proxy类的内部类,且都实现了BiFunction接口。
然后,我们接着回到 proxyClassCache.get(loader, interfaces)方法,进入此方法中看一下实现:
public V get(K key, P parameter) { //判断被代理的目标类是否有接口,没有的话将抛出异常 Objects.requireNonNull(parameter); expungeStaleEntries(); Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap == null) { ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap != null) { valuesMap = oldValuesMap; } } // create subKey and retrieve the possible Supplier<V> stored by that // subKey from valuesMap Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; while (true) { if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance V value = supplier.get(); if (value != null) { return value; } } // else no supplier in cache // or a supplier that returned null (could be a cleared CacheValue // or a Factory that wasn't successful in installing the CacheValue) // lazily construct a Factory if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } if (supplier == null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { // successfully installed Factory supplier = factory; } // else retry with winning supplier } else { if (valuesMap.replace(subKey, supplier, factory)) { // successfully replaced // cleared CacheEntry / unsuccessful Factory // with our Factory supplier = factory; } else { // retry with current supplier supplier = valuesMap.get(subKey); } } } }
这里的缓存实现暂不仔细看,主要是看ProxyClassFactory是如何生成代理类的。ProxyClassFactory是实现了BiFunction接口的apply方法。
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // prefix for all proxy class names //生成的代理类类名的前缀 private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names // 代理类名字的计数器。最后组成代理类名$Proxy0 $Proxy1 ... private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { 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; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ //非公共接口,代理类包名与接口相同 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"); } } } //公共接口包名:默认:com.sun.proxy if (proxyPkg == null) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); //组成完整的类路径 String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ //生成代理类的字节码文件 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { //根据二进制的字节码文件生成代理类的class对象 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()); } } }
接下来,我们看一下是如何生成字节码文件的:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);
ProxyGenerator是sun.misc的包。此方法为:
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), 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; }
层层调用后,最终调用generateClassFile方法才是真正生成代理类字节码文件的方法。
final byte[] var4 = var3.generateClassFile();
这个方法的源码有点长:
private byte[] generateClassFile() {//addProxyMethod系列方法就是将接口的方法和Object的hashCode,equals,toString方法添加到代理方法容器(proxyMethods) 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); } } }
注意开头的三个addProxyMethod方法是只将Object的hashcode,equals,toString方法添加到代理方法容器中,代理类除此之外并没有重写其他Object的方法,所以除这三个方法外,代理类调用其他方法的行为与Object调用这些方法的行为一样不通过Invoke。
没有完全看懂上边的代码。还可以查看addProxyMethod的源码。这里就不看了。
在动态代理中InvocationHandler是核心,每个代理实例都具有一个关联的调用处理程序(InvocationHandler)。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序(InvocationHandler)的 invoke 方法。所以对代理方法的调用都是通InvocationHadler的invoke来实现中,而invoke方法根据传入的代理对象,方法和参数来决定调用代理的哪个方法
我们来看一下生成的代理类$Proxy0:在main函数中生成代理类之前添加如下代码:
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
这会将生成的代理类的class代码写入到磁盘中项目路径下,路径为com.sun.proxy。需要提前创建。
反编译后的class文件为:
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.sun.proxy;import com.blog.jdkproxy.IUserDao;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 IUserDao { private static Method m1; private static Method m2; private static Method m3; private static Method m4; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int add() throws { try { return ((Integer)super.h.invoke(this, m3, (Object[])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int delete() throws { try { return ((Integer)super.h.invoke(this, m4, (Object[])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { 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("com.blog.jdkproxy.IUserDao").getMethod("add", new Class[0]); m4 = Class.forName("com.blog.jdkproxy.IUserDao").getMethod("delete", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }}
从上边的代理类来看,其继承了Proxy类,并且实现了目标类的接口。提供了一个使用InvocationHandler作为参数的构造方法。重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法,即可以对其进行特殊的操作,也就是说JDK的动态代理还可以代理上述三个方法。重写了接口的方法:
public final int add() throws { try { return ((Integer)super.h.invoke(this, m3, (Object[])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } }
并且利用h.invoke(this, m3, (Object[])null))来调用横切逻辑。这也能看到,利用JDK动态代理来实现时,invoke的横切逻辑(增强)是针对所有方法的。且只能对接口中的方法进行代理。
- 设计模式--JDK动态代理的实现与原理解析(2)
- 设计模式--JDK动态代理的实现与原理解析(1)
- jdk动态代理模式的原理解析
- 设计模式--CGLib动态代理的实现与解析
- JDK动态代理实现原理解析
- JDK 动态代理实现及原理解析
- 设计模式之动态代理 jdk实现
- 基于jdk动态代理的实现与源码解析
- Aop应用原理 JDK动态代理、代理模式与反射
- 细说JDK动态代理的实现原理
- JDK的动态代理实现原理理解
- 细说JDK动态代理的实现原理
- 细说JDK动态代理的实现原理
- JDK动态代理的实现及原理
- 细说JDK动态代理的实现原理
- 细说JDK动态代理的实现原理
- 细说JDK动态代理的实现原理
- JDK动态代理的实现及原理
- 量化投资成果显著:逾六成增强指基超额创收
- 解决$.ajax的回调函数值和SpringMVC返回String时冲突的问题
- 内网网站发布到外网的路由器端口映射方法
- selenium python中关于iframe的定位
- scrollview嵌套recycleview
- 设计模式--JDK动态代理的实现与原理解析(2)
- 基于java和tunnel-sdk的OSS与ODPS之间的数据连通
- 朵唯S2l 驱动安装 刷机 Imei号找回方案(应该也适合同类国产机)
- 毕业那年
- FOF常用的七种投资策略全解析
- Python实现结构体
- MAPREDUCE使用(整理)
- hihocoder Challenge 29 D. 不上升序列
- Android selector配合setSelected使用时的坑