网站导航

干燥机

当前位置:主页 > 产品展示 > 基础设备 > 干燥机 >

趣味设计模式系列:署理模式JDK动态署理源码剖析,一文便知

产品时间:2021-08-10 00:52

简要描述:

1. 图解上图主要形貌了JDK动态署理的执行历程,下面做详细分析。2. Proxy源码分析上一篇,在使用JDK动态署理的时候,借助于Proxy类,使用newProxyInstance静态方法,建立了动态署理工具,这个方法吸收三个参数,划分是目的类的类加载器、目的类实现的接口数组、自界说的InvocationHandler类,下面从该方法开始,详细分析该类如何生成的。...

详细介绍
本文摘要:1. 图解上图主要形貌了JDK动态署理的执行历程,下面做详细分析。2. Proxy源码分析上一篇,在使用JDK动态署理的时候,借助于Proxy类,使用newProxyInstance静态方法,建立了动态署理工具,这个方法吸收三个参数,划分是目的类的类加载器、目的类实现的接口数组、自界说的InvocationHandler类,下面从该方法开始,详细分析该类如何生成的。

推荐一个买球app

1. 图解上图主要形貌了JDK动态署理的执行历程,下面做详细分析。2. Proxy源码分析上一篇,在使用JDK动态署理的时候,借助于Proxy类,使用newProxyInstance静态方法,建立了动态署理工具,这个方法吸收三个参数,划分是目的类的类加载器、目的类实现的接口数组、自界说的InvocationHandler类,下面从该方法开始,详细分析该类如何生成的。本文所用JDK版本为1.8.0_161,为了保留源码英文注释的原汁原味,未对英文注释做删减,并在代码后面加注中文注释。public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h);// 验证InvocationHandler不为空 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); //获取参数类型是InvocationHandler.class的署理类结构器 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}); //传入InvocationHandler实例去结构一个署理类的实例 } 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方法生成了署理类的类工具;获取参数类型是InvocationHandler.class的署理类结构器;通过InvocationHandler实例的引用,去结构出一个署理类工具。

因为生成的署理类继续自Proxy类,子类建立实例工具时,会优先挪用父类Proxy的结构,所以最后会挪用Proxy的结构器将InvocationHandler将引用传入。下面重点看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); // 如果实现给定接口的给定加载器所界说的署理类存在,则从缓存取,否则通过ProxyClassFactory建立 }上述代码主要做了两件事:判断署理类实现的接口不能大于65535这个数;缓存存在署理类,则从缓存取,否则从ProxyClassFactory建立。

3. WeakCache源码下面将继续深入WeakCache的源码,分析proxyClassCache.get方法相关实现。final class WeakCache<K, P, V> { private final ReferenceQueue<K> refQueue = new ReferenceQueue<>(); // Reference引用行列 // the key type is Object for supporting null key private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map //缓存的底层实现, key为一级缓存, value为二级缓存。

为了支持null, map的key类型设置为Object = new ConcurrentHashMap<>(); private final ConcurrentMap<Supplier<V>, Boolean> reverseMap // 记载了所有署理类生成器是否可用, 这是为了实现缓存的逾期机制 = new ConcurrentHashMap<>(); private final BiFunction<K, P, ?> subKeyFactory; //生成二级缓存key的工厂, 这里传入的是KeyFactory private final BiFunction<K, P, V> valueFactory; //生成二级缓存value的工厂, 这里传入的是ProxyClassFactory /** * Construct an instance of {@code WeakCache} * * @param subKeyFactory a function mapping a pair of * {@code (key, parameter) -> sub-key} * @param valueFactory a function mapping a pair of * {@code (key, parameter) -> value} * @throws NullPointerException if {@code subKeyFactory} or * {@code valueFactory} is null. */ public WeakCache(BiFunction<K, P, ?> subKeyFactory, //结构器, 传入生成二级缓存key的工厂和生成二级缓存value的工厂 BiFunction<K, P, V> valueFactory) { this.subKeyFactory = Objects.requireNonNull(subKeyFactory); this.valueFactory = Objects.requireNonNull(valueFactory); } /** * Look-up the value through the cache. This always evaluates the * {@code subKeyFactory} function and optionally evaluates * {@code valueFactory} function if there is no entry in the cache for given * pair of (key, subKey) or the entry has already been cleared. * * @param key possibly null key * @param parameter parameter used together with key to create sub-key and * value (should not be null) * @return the cached value (never null) * @throws NullPointerException if {@code parameter} passed in or * {@code sub-key} calculated by * {@code subKeyFactory} or {@code value} * calculated by {@code valueFactory} is null. */ public V get(K key, P parameter) { Objects.requireNonNull(parameter); //这里要求实现的接口不能为空 expungeStaleEntries(); //清除逾期的缓存 Object cacheKey = CacheKey.valueOf(key, refQueue); //将ClassLoader包装成CacheKey, 作为一级缓存的key // lazily install the 2nd level valuesMap for the particular cacheKey ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); // 懒加载获取二级缓存 if (valuesMap == null) { //如果凭据ClassLoader没有获取到对应的值 ConcurrentMap<Object, Supplier<V>> oldValuesMap // 如果不存在则放入,否则返回原先的值 = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap != null) { //如果oldValuesMap有值, 说明放入失败 valuesMap = oldValuesMap; } } // create subKey and retrieve the possible Supplier<V> stored by that // subKey from valuesMap Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); //凭据署理类实现的接口数组来生成二级缓存key, 分为key0, key1, key2, keyx Supplier<V> supplier = valuesMap.get(subKey); //这里通过subKey获取到二级缓存的值 Factory factory = null; while (true) { //这个循环提供了轮询机制, 如果条件为假就继续重试直到条件为真为止 if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance V value = supplier.get(); // 在这里supplier可能是一个Factory也可能会是一个CacheValue 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) { //缓存中没有supplier factory = new Factory(key, parameter, subKey, valuesMap); //新建一个Factory实例作为subKey对应的值 } if (supplier == null) { // supplier返回null supplier = valuesMap.putIfAbsent(subKey, factory); //到这里讲明subKey没有对应的值, 就将factory作为subKey的值放入 if (supplier == null) { // successfully installed Factory supplier = factory; //到这里讲明乐成将factory放入缓存 } // else retry with winning supplier } else { //Factory 没有乐成装入缓存 if (valuesMap.replace(subKey, supplier, factory)) { //期间可能其他线程修改了值, 那么就将原先的值替换 // successfully replaced // cleared CacheEntry / unsuccessful Factory // with our Factory supplier = factory; //乐成将factory替换成新的值 } else { // retry with current supplier supplier = valuesMap.get(subKey); //替换失败, 继续使用原先的值 } } } } //后面省略WeakCache的成员变量map,是通过ConcurrentMap来完成的,key为一级缓存, value为二级缓存,类型也是ConcurrentMap;reverseMap是为了实现缓存的逾期机制;subKeyFactory是二级缓存key的生成工厂,通过结构器传入Proxy类的KeyFactory,valueFactory是二级缓存value的生成工厂,通过结构器传入Proxy类的ProxyClassFactory。get方法大致做了如下几步:将ClassLoader包装成CacheKey, 作为一级缓存的key;懒加载获取二级缓存valuesMap;凭据署理类实现的接口数组来生成二级缓存subKey;这里通过二级缓存的subKey获取到二级缓存的值;若缓存中没有值、或者返回null、或者Factory实例没有乐成装载,通过轮询方式获取二级缓存的值,直到缓存的值被装载进去。这里的二级缓存的值是一个Factory实例,最终署理类的值是通过Factory这个工厂来获得的。

/** * A factory {@link Supplier} that implements the lazy synchronized * construction of the value and installment of it into the cache. */ private final class Factory implements Supplier<V> { private final K key; //一级缓存key, 凭据ClassLoader生成 private final P parameter; //署理类实现的接口数组 private final Object subKey; //二级缓存key, 凭据接口数组生成 private final ConcurrentMap<Object, Supplier<V>> valuesMap; //二级缓存 Factory(K key, P parameter, Object subKey, ConcurrentMap<Object, Supplier<V>> valuesMap) { this.key = key; this.parameter = parameter; this.subKey = subKey; this.valuesMap = valuesMap; } @Override public synchronized V get() { // serialize access // re-check Supplier<V> supplier = valuesMap.get(subKey); //再次检查并获取二级缓存内里的Supplier, 用来验证是否是Factory自己 if (supplier != this) { //在这里验证supplier是否是Factory实例自己, 如果不是则返回null让挪用者继续轮询重试; // something changed while we were waiting: // might be that we were replaced by a CacheValue // or were removed because of failure -> // return null to signal WeakCache.get() to retry // the loop return null; } // else still us (supplier == this) // create new value V value = null; try { value = Objects.requireNonNull(valueFactory.apply(key, parameter)); // 通过valueFactory生成署理类, 实际传入ProxyClassFactory去生成署理类 } finally { if (value == null) { // remove us on failure valuesMap.remove(subKey, this); //如果生成署理类失败, 就将这个二级缓存删除 } } // the only path to reach here is with non-null value assert value != null; //只有value的值不为空才气到达这里 // wrap value with CacheValue (WeakReference) CacheValue<V> cacheValue = new CacheValue<>(value); //使用弱引用包装生成的署理类 // put into reverseMap reverseMap.put(cacheValue, Boolean.TRUE); //将包装后的cacheValue作为可用的署理类,放入reverseMap中 // try replacing us with CacheValue (this should always succeed) if (!valuesMap.replace(subKey, this, cacheValue)) { //将包装后的cacheValue放入二级缓存中, 这个操作必须乐成, 否则就报错 throw new AssertionError("Should not reach here"); } // successfully replaced us with new CacheValue -> return the value // wrapped by it return value; //最后返回未被弱引用包装的原始署理类value } }内部类Factory的get方法是使用synchronized关键字举行了同步,主要做了如下几步:检查并获取二级缓存内里的Supplier, 验证是否是Factory自己;如果1不是,则返回null,让挪用者继续轮询重试;如果1是,则通过valueFactory生成署理类, 实际传入ProxyClassFactory去生成署理类;如果生成署理类失败, 就将这个二级缓存删除;断言,只有署理类生成乐成才气继续下面步骤;使用弱引用包装生成的署理类;将包装后的cacheValue作为可用的署理类,放入reverseMap中;将包装后的cacheValue放入二级缓存中, 且操作必须乐成;最后返回未被弱引用包装的原始署理类value。至此,WeakCache一级缓存和二级缓存实现的原理,已经论述清楚,上述历程中的第3步,二级缓存key生成的原理,是怎样通过Proxy的内部类ProxyClassFactory来生成署理类的,下面继续深入ProxyGenerator这个类,分享署理类的字节码生成历程。4. ProxyClassFactory源码分析 /** * A factory function that generates, defines and returns the proxy class given * the ClassLoader and array of interfaces. */ 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 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) { // intf是否可以由指定的类加载举行加载 throw new IllegalArgumentException( intf + " is not visible from class loader"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { // intf是否是一个接口 throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { // intf在数组中是否有重复 throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in //生成署理类的包名 int accessFlags = Modifier.PUBLIC | Modifier.FINAL; //生成署理类的会见标志, 默认是public 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)) { //如果接口的会见标志不是public, 那么生成署理类的包名和接口包名相同 accessFlags = Modifier.FINAL; //生成的署理类的会见标志设置为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)) { //署理类如果实现差别包的接口, 而且接口都不是public的, 那么就会在这里报错 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 + "."; //如果接口会见标志都是public的话, 那生成的署理类都放到默认的包下:com.sun.proxy } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); //生成署理类的序号 String proxyName = proxyPkg + proxyClassNamePrefix + num; //生成署理类的全限命名, 包名+前缀+序号, 例如:com.sun.proxy.$Proxy0 /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); // 用ProxyGenerator来生成字节码, 该类放在sun.misc包下 try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); //凭据二进制文件生成相应的Class实例 } 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()); } } }上述代码主要完成以下步骤:判断接口是否由指定类的加载器加载、是否是接口、接口是否重复;指定生成包名类名的相关规则,接口会见标志都是public,署理类都放到默认的com.sun.proxy包下,接口的会见标志不是public, 那么生成署理类的包名和接口包名相同;通过ProxyGenerator类的generateProxyClass方法生成字节码文件;凭据二进制文件生成相应的署理类实例。

第3步是关键,下面将进一步分析ProxyGenerator类的generateProxyClass方法。5. ProxyGenerator源码分析由于ProxyGenerator类不在jdk中,需要下载openjdk才气看到源码,openjdk1.8官网下载地址如下http://hg.openjdk.java.net/jdk8/jdk8/jdk/archive/tip.zip,解压后在openjdkjdksrcshareclassessunmisc下面。

/** * Generate a class file for the proxy class. This method drives the * class file generation process. */ private byte[] generateClassFile() { /* ============================================================ * Step 1: Assemble ProxyMethod objects for all methods to * generate proxy dispatching code for. */ //第一步, 将所有的方法组装成ProxyMethod工具 /* * Record that proxy methods are needed for the hashCode, equals, * and toString methods of java.lang.Object. This is done before * the methods from the proxy interfaces so that the methods from * java.lang.Object take precedence over duplicate methods in the * proxy interfaces. */ addProxyMethod(hashCodeMethod, Object.class); //为署理类生成hashCode署理方法 addProxyMethod(equalsMethod, Object.class); //为署理类生成equals署理方法 addProxyMethod(toStringMethod, Object.class); //为署理类生成toString署理方法 /* * Now record all of the methods from the proxy interfaces, giving * earlier interfaces precedence over later ones with duplicate * methods. */ for (Class<?> intf : interfaces) { //遍历每一个接口的每一个方法, 而且为其生成ProxyMethod工具 for (Method m : intf.getMethods()) { addProxyMethod(m, intf); } } /* * For each set of proxy methods with the same signature, * verify that the methods' return types are compatible. */ for (List<ProxyMethod> sigmethods : proxyMethods.values()) { //对于具有相同签名的署理方法, 磨练方法的返回值是否兼容 checkReturnTypes(sigmethods); } /* ============================================================ * Step 2: Assemble FieldInfo and MethodInfo structs for all of * fields and methods in the class we are generating. */ //第二步, 组装要生成的class文件的所有的字段信息和方法信息 try { methods.add(generateConstructor()); //添加结构器方法 for (List<ProxyMethod> sigmethods : proxyMethods.values()) { //遍历缓存中的署理方法 for (ProxyMethod pm : sigmethods) { // add static field for method's Method object fields.add(new FieldInfo(pm.methodFieldName, //添加署理类的静态字段 "Ljava/lang/reflect/Method;", ACC_PRIVATE | ACC_STATIC)); // generate code for proxy method and add it methods.add(pm.generateMethod()); //添加署理类的署理方法 } } methods.add(generateStaticInitializer()); //添加署理类的静态字段初始化方法 } catch (IOException e) { throw new InternalError("unexpected I/O Exception", e); } if (methods.size() > 65535) { //验证方法和字段荟萃不能大于65535 throw new IllegalArgumentException("method limit exceeded"); } if (fields.size() > 65535) { throw new IllegalArgumentException("field limit exceeded"); } /* ============================================================ * Step 3: Write the final class file. */ //第三步, 写入最终的class文件 /* * Make sure that constant pool indexes are reserved for the * following items before starting to write the final class file. */ cp.getClass(dotToSlash(className)); //验证常量池中存在署理类的全限命名 cp.getClass(superclassName); //验证常量池中存在署理类父类的全限命名, 父类名为:"java/lang/reflect/Proxy" for (Class<?> intf: interfaces) { //验证常量池存在署理类接口的全限命名 cp.getClass(dotToSlash(intf.getName())); } /* * Disallow new constant pool additions beyond this point, since * we are about to write the final constant pool table. */ cp.setReadOnly(); //接下来要开始写入文件了,设置常量池只读 ByteArrayOutputStream bout = new ByteArrayOutputStream(); DataOutputStream dout = new DataOutputStream(bout); try { /* * Write all the items of the "ClassFile" structure. * See JVMS section 4.1. */ // u4 magic; dout.writeInt(0xCAFEBABE); //1.写入魔数 // u2 minor_version; dout.writeShort(CLASSFILE_MINOR_VERSION); //2.写入次版本号 // u2 major_version; dout.writeShort(CLASSFILE_MAJOR_VERSION); //3.写入主版本号 cp.write(dout); // (write constant pool) //4.写入常量池 // u2 access_flags; dout.writeShort(accessFlags); //5.写入会见修饰符 // u2 this_class; dout.writeShort(cp.getClass(dotToSlash(className))); //6.写入类索引 // u2 super_class; dout.writeShort(cp.getClass(superclassName)); //7.写入父类索引, 生成的署理类都继续自Proxy // u2 interfaces_count; dout.writeShort(interfaces.length); //8.写入接口计数值 // u2 interfaces[interfaces_count]; for (Class<?> intf : interfaces) { dout.writeShort(cp.getClass( //9.写入接口荟萃 dotToSlash(intf.getName()))); } // u2 fields_count; dout.writeShort(fields.size()); //10.写入字段计数值 // field_info fields[fields_count]; for (FieldInfo f : fields) { f.write(dout); //11.写入字段荟萃 } // u2 methods_count; dout.writeShort(methods.size());//12.写入方法计数值 // method_info methods[methods_count]; for (MethodInfo m : methods) { m.write(dout); //13.写入方法荟萃 } // u2 attributes_count; dout.writeShort(0); // (no ClassFile attributes for proxy classes) //14.写入属性计数值, 署理类class文件没有属性所以为0 } catch (IOException e) { throw new InternalError("unexpected I/O Exception", e); } return bout.toByteArray(); //转换成二进制数组输出 }上述代码主要完成以下步骤:收集所有要生成的署理方法,将其包装成ProxyMethod工具并注册到Map荟萃中;收集所有要为Class文件生成的字段信息和方法信息;完成了上面的事情后,开始组装Class文件。其中第2步是焦点,为署理类生成字段和方法,完成以下步骤:为署理类生成一个带参结构器,传入InvocationHandler实例的引用并挪用父类的带参结构器;遍历署理方法Map荟萃,为每个署理方法生成对应的Method类型静态域,并将其添加到fields荟萃中;遍历署理方法Map荟萃,为每个署理方法生成对应的MethodInfo工具,并将其添加到methods荟萃中;为署理类生成静态初始化方法,该静态初始化方法主要是将每个署理方法的引用赋值给对应的静态字段。

最终引用上一篇的例子,生成的署理类如下://// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.sun.proxy;import com.wzj.proxy.v9.Sellalbe;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 Sellalbe { private static Method m1; private static Method m3; private static Method m2; 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}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void secKill() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } 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 hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("com.wzj.proxy.v9.Sellalbe").getMethod("secKill"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }}到此为止,JDK动态署理的生成原理基本上分析完了,笔者通过多次调试源码,并联合英文注解,明白并翻译其中的主要步骤,读者可以凭据本文的分析,自己调试JDK源码,相信也会有纷歧样的收获,文章如有分析不恰当之处,接待交流,一起进步。


本文关键词:推荐一个买球app,趣味,设计模式,系列,署理,模式,JDK,动态,源码

本文来源:推荐一个买球app-www.bbbmz.com

 


产品咨询

留言框

  • 产品:

  • 留言内容:

  • 您的单位:

  • 您的姓名:

  • 联系电话:

  • 常用邮箱:

  • 详细地址:

推荐产品

如果您有任何问题,请跟我们联系!

联系我们

Copyright © 2006-2021 www.bbbmz.com. 推荐一个买球app科技 版权所有 备案号:ICP备98736617号-8

地址:内蒙古自治区锡林郭勒盟二连浩特市一央大楼554号

在线客服 联系方式 二维码

服务热线

0489-60365834

扫一扫,关注我们