internalerror
很多同学在进行编程学习时缺乏系统学习的资料。本页面基于internalerror内容,从基础理论到综合实战,通过实用的知识类文章,标准的编程教程,丰富的视频课程,为您在internalerror相关知识领域提供全面立体的资料补充。同时还包含 inner join、innerhtml、innerjoin 的知识内容,欢迎查阅!
internalerror相关知识
-
视频直播iOS端技术作者:陶金亮 网易通信与视频资深开发工程师 随着网络基础建设的发展和资费的下降,在这个内容消费升级的时代,文字、图片无法满足人们对视觉的需求,因此视频直播应运而生。承载了实时性Real-Time和交互性的直播云服务是直播覆盖各行各业的新动力。 直播架构 想必了解过直播的人都清楚直播主要分为3部分:推流->流媒体服务器->拉流。 而我们今天需要讲的就是推流这部分,它主要包括音视频采集,音视频前处理,音视频编码,推流和传输4个方面。但是由于网络的复杂性和大数据的统计,推流还需要有全局负载均衡调度GSLB(Global Server Load Balance),以及实时的统计数据上报服务器,包括提供频道管理给用户运营,因此推流SDK需要接入GSLB中心调度,统计服务器,心跳服务器,用于推流分配到网络最好的节点,有大数据的统计和分析。 下图涵盖了直播相关的所有服务,红色小标的线条代表指令流向,绿色小标的线条代表数据流向。
-
Hadoop两个主要模块以及MapReduce程序的具体实现Hadoop系统简介 Hadoop 是一个开源分布式计算平台。以hadoop 分布式文件系统(HDFS)和MapReduce分布式编程模型为核心的Hadoop 为用户提供了分布式基础架构。HDFS的高容错性,高吞吐量等优点允许用户将 Hadoop部署在低廉的硬件上,形成分布式系统。MapReduce分布式编程模型允许用户在不了解分布式系统底层细节的情况下开发并行应用程序。所以用户可以利用Hadoop轻松组织计算机资源,从而搭建自己的分布式计算平台,并且可以充分利用集群的计算和存储能力,完成海量数据的运算。 HDFS体系结构
-
小程序入门教程及实例目录 开发环境 目录结构 WXML组件 WXSS 数据绑定 条件渲染 列表渲染 模版 事件 引用 路由传参 API 实例TodoList 1.开发环境 开发工具下载(https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html) 安装之后,和微信web开发者工具一样,扫码登录即可,不同的是,创建一个小程序需要填写AppID,如果没有AppID的话,点击‘无AppID’即可 2.目录结构 一个小程序由两部分组成:框架主体部分、框架页面部分 框架主体部分 框架主体部分包含三个文件,位于项目的根目
-
extend基础 Vue 构造器1、在Vue页面中创建一个构造器:// 创建构造器 var Profile = Vue.extend( { template: '<p style="color: red">{{firstName}} {{lastName}} aka {{alias}}</p>', data: function () { &
internalerror相关课程
internalerror相关教程
- 5. 其他异常对象 URIError 表示以一种错误的方式使用全局URI处理函数而产生的错误;TypeError 值的类型非预期类型时发生的错误;SyntaxError 尝试解析语法上不合法的代码的错误;ReferenceError 当一个不存在的变量被引用时发生的错误;RangeError 当一个值不在其所允许的范围或者集合中抛出的异常;InternalError 表示出现在 JavaScript 引擎内部的错误。非标准对象,不建议使用;EvalError 本对象代表了一个关于 eval 函数的错误.此异常不再会被 JavaScript 抛出,但是EvalError对象仍然保持兼容性。这些异常对象的使用和 Error 几乎一致。浏览器碰到对应的异常,也会抛出。try { console.log(notDefinedVariable);} catch (e) { console.error(e);}因为 notDefinedVariable 并没有定义,所以浏览器会抛出 ReferenceError 异常,同时提示变量没有定义。
- 8.2 源码分析论证 第一步我们先从 Proxy.newProxyInstance 方法探究,通过它在外部更为直观是可以获取代理类对象。class Client { public static void main(String[] args) { IPurchaseHouse houseOwner = new HouseOwner(); DynamicProxy dynamicProxy = new DynamicProxy(houseOwner); //第一步: 从Proxy.newProxyInstance方法入手 IPurchaseHouse agentA = (IPurchaseHouse) Proxy.newProxyInstance( houseOwner.getClass().getClassLoader(), new Class[]{IPurchaseHouse.class}, dynamicProxy ); agentA.inquiryPrice(); agentA.visitHouse(); agentA.payDeposit(); agentA.signAgreement(); agentA.payMoney(); agentA.getHouse(); }}第二步进入 Proxy.newProxyInstance 方法的定义,Proxy.newProxyInstance 有三个参数:loader(ClassLoader): 这个参数是实际被代理类的类加载器实例;interfaces(Class<?>[]): 代理类和被代理类共同实现的接口的 Class 数组;h(InvocationHandler): 代理拦截器接口,一般需要使用子类去实现该接口或匿名类去实现。 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone();//将interfaces的Class数组clone一份副本,赋值给intfs final SecurityManager sm = System.getSecurityManager(); if (sm != null) {//检查创建一个新的代理类需要权限 checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ //注意点1: getProxyClass0方法拿到代理类的Class对象实例cl //注意传入的参数就是从外部传入的loader(被代理类的类加载器)、intfs(被代理类实现所接口的Class[]的副本) Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } //注意点2: 拿到cl实例后,就通过反射机制创建代理类实例 final Constructor<?> cons = cl.getConstructor(constructorParams);//先拿到代理类的构造器Constructor实例cons final InvocationHandler ih = h; //检查代理类构造器是否是公有的public权限, 不是就会通过AccessController去修改访问权限以致于可以创建代理类实例 if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true);//将访问权限设置为可访问的 return null; } }); } //注意点3: 拿到构造器实例cons后,就到了最为关键的也就是最后一步,创建代理类实例。 //但是需要注意的是构造器反射传入的参数是h,也就是传入的InvocationHandler的实例,也可以进一步推论生成的代理类中存在以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); } }再一次来梳理下 newProxyInstance 源码流程:首先传入 loader、interfaces、h 三个参数,先将 interfacesclone 一份副本保存在 intfs 中,然后检查创建一个新的代理类所需要的权限,接着到了我们第一个注意点 1,就是通过 getProxyClass0 方法 (需要传入 loader 和 intfs 参数) 获得代理类的 Class 对象实例。拿到了代理类实例后,我们就通过反射的机制创建代理类实例;到了我们的 注意点二,通过代理类 Class 对象 cl 获得构造器对象 cons,并检查构造器对象是否是 public, 否则就强行修改访问权限;最后到了注意点三,通过 cons.newInstance 创建代理类对象,并且构造器反射中传入 h(InvocationHandler对象),说明我们可以推断一下生成的代理类中存在以 InvocationHandler 为参数的构造器。第三步进入 getProxyClass0 方法,传入的参数 loader 和 intfs,在该方法内部会委托给 proxyClassCache 的 get 方法,如果给定的类加载器中定义的代理类实现了给定的接口,直接返回缓存中的副本,否则它将通过 ProxyClassFactory 创建代理类. 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 //请注意上面那段英文注释: 如果给定的类加载器中定义的代理类实现了给定的接口, //那么就会直接返回缓存中的副本,否则它将通过ProxyClassFactory创建代理类 //注意点1: proxyClassCache;注意点2: ProxyClassFactory return proxyClassCache.get(loader, interfaces); }第四步 proxyClassCache 的介绍和定义,请注意创建 proxyClassCache 传入的构造器两个参数分别是: KeyFactory 和 ProxyClassFactory: /** * a cache of proxy classes */ private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());proxyClassCache 是一个 WeakCache<K,P,V> 对象,WeakCache<K,P,V> 中的 K 表示 key 值,P 代表参数,V 代表存储的值。此类用于缓存 (key, sub-key) -> value 键值对。内部具体实现是借助了 ConcurentMap<Object, ConcurrentMap<Object, Supplier<V>>>,Supplier 是一个接口,就一个 get 方法用于获得值,不过是泛型 V 的包装类,第一个 Object 就是 key(这里表达式不用泛型 K 是因为 key 值可以为 null),第二个就是 sub-key,那么它对应着什么呢?而且具体的缓存中也没有泛型 P 呢,这就需要引出另外一个函数接口 BiFunction<T, U, R>, 该接口内部存在 R apply(T t, U u) 方法,这个方法意思就是根据传入两个泛型 T 和 U 的值经过一定计算得到泛型 R 的值。在 WeakCache<K,P,V> 类中存在两个 BiFunction 对象:final class WeakCache<K, P, V> { private final ReferenceQueue<K> refQueue = new ReferenceQueue<>(); // the key type is Object for supporting null key private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>(); private final ConcurrentMap<Supplier<V>, Boolean> reverseMap = new ConcurrentHashMap<>(); private final BiFunction<K, P, ?> subKeyFactory; private final BiFunction<K, P, V> valueFactory; public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) { //根据K,P得到sub-key算法 this.subKeyFactory = Objects.requireNonNull(subKeyFactory); //根据K,P得到value算法 this.valueFactory = Objects.requireNonNull(valueFactory); } ...}在 WeakCahe 类中只有一个核心 get 方法,里面包含了整个缓存的逻辑,注意我们获取代理类 Class 对象,就是通过 proxyClassCache.get(loader, interfaces); 实际上就是调用 WeakCache 中的 get 方法。//K泛型是一级map的缓存key, P泛型传入的参数,分别对应外部传入的 loader和 interfacespublic V get(K key, P parameter) { ... //通过传入一级map的key,通过CacheKey拿到最终 Object cacheKey = CacheKey.valueOf(key, refQueue); // 懒初始化cacheKey对应的二级valuesMap, 如果valuesMap为空,就会新创建一个空的ConcurrentMap的valueMap,put到一级缓存map中 ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap == null) { //如果valuesMap为空,就会新创建一个空的ConcurrentMap的valueMap ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>()); //如果内部已经存在原来的oldValuesMap直接用它 if (oldValuesMap != null) { valuesMap = oldValuesMap; } } //------注意点1: subKeyFactory.apply(key, parameter)----- //根据传入的一级map的key和参数parameter,通过subKeyFactory中的apply方法获得sub-key, Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); //然后通过我们的sub-key,从二级缓存的valuesMap中取的supplier对象 Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; while (true) { if (supplier != null) { //supplier这个对象可能是Factory或CacheValue<V>对象, //那么也就是supplier.get()方法可能是调用了Factory中的get方法或CacheValue<V>中的get方法//--------注意点2: supplier.get()----- V value = supplier.get(); //如果value不为空就返回value,结束整个get方法调用 if (value != null) { return value; } } //如果缓存中没有supplier对象 //或者supplier中get返回是null //或者Factory对象没有在CacheValue中被成功创建 //factory为null,就会创建一个新的Factory实例 if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } //supplier为null if (supplier == null) { //根据新创建的factory和subKey拿到supplier对象,如果valuesMap中存在subKey, factory键值对,就返回已经存在的值,没有直接返回null supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { //如果拿到supplier为null,supplier就变为了factory,这就是前面说supplier为一个factory supplier = factory; } // else retry with winning supplier } else { if (valuesMap.replace(subKey, supplier, factory)) { supplier = factory; } else { //通过valuesMap.get()拿到supplier supplier = valuesMap.get(subKey); } } } }我们来一起梳理下 WeakCache 的逻辑:首先 proxyClassCache 就是一个 WeakCache 实例对象,它有两个构造器参数 subKeyFactory 和 valueFactory, 创建 proxyClassCache 实例对应传入的是 proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()) 中的 KeyFactory 和 ProxyClassFactory。然后在 WeakCache 内部存在二级 ConcurrentHashMap, 一级 map 的 key 就是 get 方法传入的 key, 通过这个 key 拿到 cacheKey, 从而拿到对应的 valuesMap二级map。然后又通过根据传入的一级 map 的 key 和参数 parameter,subKeyFactory 中的 apply 方法获得 sub-key, 通过 sub-key 拿到二级 map 中存储的 Supplier 对象,它可能是一个 CacheValue 也有可能是一个 Factory,最终通过 Factory 的 get 方法拿到实际的值。对于上述有两个核心注意点:注意点 1 -----> 获取 subKey 过程: 通过 subKeyFactory.apply(key,parameter) 拿到 sub-key://weakCache调用处: Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); //KeyFactory的定义 private static final class KeyFactory implements BiFunction<ClassLoader, Class<?>[], Object> { @Override public Object apply(ClassLoader classLoader, Class<?>[] interfaces) { //可以看到是根据被代理类实现的接口的Class数组长度来决定选用哪一种subKey switch (interfaces.length) { //对于被代理类只实现了1个接口情况,也是最频繁一种 case 1: return new Key1(interfaces[0]); // the most frequent //对于被代理类只实现了2个接口情况 case 2: return new Key2(interfaces[0], interfaces[1]); //对于被代理类只实现了0个接口情况 case 0: return key0; //对于被代理类只实现了超过2个接口情况 default: return new KeyX(interfaces); } } }注意点 2----> supplier.get () 获取 value 的过程:我们都知道 supplier 对应的可以是 Factory 对象,也就是最后会调用 Factory 中的 get 方法。 @Override public synchronized V get() { // serialize access // 再一次检查supplier,如果传入从valuesMap拿到的不等于当前Factory对象,因为它可能已经变成CacheValue了,那就直接返回null Supplier<V> supplier = valuesMap.get(subKey); if (supplier != this) { return null; } //创建一个新的value V value = null; try { //注意点出现,value最终会通过valueFactory.apply(key, parameter)拿到 value = Objects.requireNonNull(valueFactory.apply(key, parameter)); } finally { if (value == null) { // remove us on failure valuesMap.remove(subKey, this); } } // 判断value是否为null assert value != null; // 将拿到的value包装成一个CacheValue CacheValue<V> cacheValue = new CacheValue<>(value); // 尝试把valuesMap中的对应subKey的Factory替换成cacheValue, //这就是为什么前面说过valuesMap中取出的Supplier可能是Factory可能是CacheValue,有没有种偷梁换柱的赶脚 if (valuesMap.replace(subKey, this, cacheValue)) { //替换成功后,并把cacheValue put到reverseMap中 reverseMap.put(cacheValue, Boolean.TRUE); } else { throw new AssertionError("Should not reach here"); } // 成功替换了新的CacheValue,并返回最终的值 return value; }通过上述代码分析,我们知道最终 value 获取是来自于 valueFactory 中 apply 方法,还记得 valueFactory 是啥吗?没错它就是 ProxyClassFactory 也就是最终定位到了 ProxyClassFactory 中的 apply 方法。这也就是为什么之前说如果缓存中有直接从缓存中返回缓存的副本,没有就在 ProxyClassFactory 中创建代理对象。第五步进入 ProxyClassFactory 中的 apply 方法进行探究,这是创建新的代理类 Class 对象唯一来源。 private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // 所有生成的代理类名称统一前缀$Proxy private static final String proxyClassNamePrefix = "$Proxy"; 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) { //验证类加载器是否将此接口的名称解析为同一个Class对象 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"); } //验证interfaceClass的Class对象是否是一个接口 if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } //验证此接口不是重复的 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; //记录非公共代理接口的包,以便proxy类将在同一个包中定义。验证所有非公共代理接口是否在同一个包中 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; //生成确定的代理类Class文件的byte数组 //------注意点ProxyGenerator.generateProxyClass----- byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { //通过defineClass0方法传入被代理类的类加载器、代理类唯一名称、生成的代理类文件反序列化成一个代理类的Class对象 return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); } } }再重新梳理一下 ProxyClassFactory 中的 apply 中的逻辑,首先做一些接口验证操作,然后通过 ProxyGenerator.generateProxyClass 生成确定的代理类 Class 文件的 byte 数组,最后通过 defineClass0 方法传入被代理类的类加载器、代理类唯一名称、生成的代理类文件反序列化成一个代理类的 Class 对象第六步进入 ProxyGenerator 中的 generateProxyClass 方法进行探究,主要通过它来生成代理类 Class 文件。generateProxyClass 方法传入的参数主要有: proxyName (唯一代理类名称), interfaces (需要代理的接口 Class 数组),accessFlags (访问权限标识): public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) { ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2); //-----注意点----调用ProxyGenerator中的generateClassFile方法 final byte[] var4 = var3.generateClassFile(); //是否需要把生成Class文件保存在本地文件中,这个标识可以从外部进行配置 //boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles")) if (saveGeneratedFiles) { AccessController.doPrivileged(new PrivilegedAction<Void>() { 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)); Files.createDirectories(var3); var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class"); } else { var2 = Paths.get(var0 + ".class"); } 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() 方法,该方法主要生成 Class 文件: private byte[] generateClassFile() { //---注意点1----在生成的代理类中加入Object类几个默认方法比如常见的hashCode、equal、toString方法 this.addProxyMethod(hashCodeMethod, Object.class); this.addProxyMethod(equalsMethod, Object.class); this.addProxyMethod(toStringMethod, Object.class); //取出代理类的接口的Class数组 Class[] var1 = this.interfaces; int var2 = var1.length; int var3; Class var4; //----注意点2---遍历代理类的接口的Class数组,将代理类接口中的方法加入生成的代理类中 for(var3 = 0; var3 < var2; ++var3) { var4 = var1[var3]; //获得每个接口中定义的所有方法Method对象 Method[] var5 = var4.getMethods(); int var6 = var5.length; //然后再遍历所有的Method对象,并把它加入到生成的代理类中 for(int var7 = 0; var7 < var6; ++var7) { Method var8 = var5[var7]; this.addProxyMethod(var8, var4); } } ... try { //----注意点3 生成的代理类中加入生成构造器方法generateConstructor---- this.methods.add(this.generateConstructor()); var11 = this.proxyMethods.values().iterator(); ... //----注意点4 生成的代理类中加入生成静态初始化块---- this.methods.add(this.generateStaticInitializer()); } catch (IOException var10) { throw new InternalError("unexpected I/O Exception", var10); } ... //创建字节数组输出流 ByteArrayOutputStream var13 = new ByteArrayOutputStream(); DataOutputStream var14 = new DataOutputStream(var13); try { ... var14.writeShort(this.fields.size()); var15 = this.fields.iterator(); //往输出流写入生成代理类Filed字段相关信息 while(var15.hasNext()) { ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next(); var20.write(var14); } var14.writeShort(this.methods.size()); var15 = this.methods.iterator(); //往输出流写入生成代理类Method方法相关信息 while(var15.hasNext()) { ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next(); var21.write(var14); } var14.writeShort(0); //返回最终的Class文件的字节数组 return var13.toByteArray(); } catch (IOException var9) { throw new InternalError("unexpected I/O Exception", var9); } } }以上就是整个动态代理中代理类生成代码的过程,为了进一步弄明白动态的机制,比如 invoke 是怎么调用的呢。不妨我们把生成代码保存在本地文件中,然后一起来看下生成的代理类长啥样。public final class $Proxy1 extends Proxy implements IPurchaseHouse { private static Method m1; private static Method m7; private static Method m8; private static Method m2; private static Method m4; private static Method m3; private static Method m6; private static Method m0; private static Method m5; //----注意点1 生成代理类中的构造器中有个InvocationHandler参数---- public $Proxy1(InvocationHandler var1) throws { super(var1);//并把它传给它的父类Proxy中的h(InvocationHandler) } //生成equals方法 public final boolean equals(Object var1) throws { try { //---注意点出现super.h.invoke--- //委托父类`Proxy`中的`h`中的`invoke`方法来实现调用,并把当前生成的代理类实例this、当前方法对应的`Method`对象和参数数组`args`通过`invoke`回调出去,此时`InvocationHandler`子类中的`invoke`方法就会得以触发 return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } //生成Object类中默认的hashCode方法 public final int hashCode() throws { try { //---注意点出现super.h.invoke--- return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } //生成Object类中默认的toString方法 public final String toString() throws { try { //---注意点出现super.h.invoke--- return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } //生成代理接口中的payDeposit方法 public final void payDeposit() throws { try { //---注意点出现super.h.invoke 同理--- super.h.invoke(this, m7, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } //生成代理接口中的signAgreement方法 public final void signAgreement() throws { try { //---注意点出现super.h.invoke 同理--- super.h.invoke(this, m8, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } //生成代理接口中的payMoney方法 public final void payMoney() throws { try { //---注意点出现super.h.invoke 同理--- super.h.invoke(this, m4, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } //生成代理接口中的getHouse方法 public final void getHouse() throws { try { //---注意点出现super.h.invoke 同理--- super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } //生成代理接口中的visitHouse方法 public final void visitHouse() throws { try { //---注意点出现super.h.invoke 同理--- super.h.invoke(this, m6, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } //生成代理接口中的inquiryPrice方法 public final void inquiryPrice() throws { try { //---注意点出现super.h.invoke 同理--- super.h.invoke(this, m5, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } //生成的静态初始化块中,通过反射拿到对应的方法Method对象, //其中包括了Object中的方法和代理接口中的方法 static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m7 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("payDeposit"); m8 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("signAgreement"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m4 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("payMoney"); m3 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("getHouse"); m6 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("visitHouse"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); m5 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("inquiryPrice"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }}其实当你看到了生成的代理类的代码后,你就会发现动态代理的机制就非常一目了然。你也就明白了 InvocationHandler 中的 invoke 方法什么时候调用了。那我们再来整体梳理下动态代理核心机制,其实最为核心的就是 InvocationHandler:首先,我们需要去实现一个 InvocationHandler 的子类,重写它的 invoke 方法,该方法中会回调三个参数: Object proxy, Method method, Object[] args, 然后在我们在 invoke 方法中只需要通过调用 method 的 invoke 方法,并传入 args 参数。然后我们去创建一个代理类实例是通过 Proxy.newProxyInstance, 会传入 InvocationHandler 子类实例,并把这个 InvocationHandler 子类实例作为生成新的代理类的构造器函数参数,并把这个参数传给新的代理类的父类 Proxy,在 Proxy 中会维护这个 InvocationHandler 子类实例 h。然后通过上述生成的代理类代码来看,会把所有方法都转成对应的 Method 对象,并在静态初始化块中通过反射进行初始化,然后每个方法内部调用实现,都会委托父类 Proxy 中的 h 中的 invoke 方法来实现调用,并把当前生成的代理类实例、当前方法对应的 Method 对象和参数数组 args 通过 invoke 回调出去,此时 InvocationHandler 子类中的 invoke 方法会得以触发,那么在其内部又转为 method 调用它的 invoke 方法,并传入 args 参数就相当于利用反射去调用这个方法。
- Hibernate 继承映射 零基础学习企业级 JDBC 优秀框架
- 11.5【应用】添加用户角色 .Net Core 开发电商后端API
- 2-1 有趣、简单的算法问题 摆脱题海,高频经典题目归纳讲解;以练代学,短期高效
- 前端物料体系介绍和前端组件平台架构设计 一句话介绍
internalerror相关搜索
-
inline
inner join
innerhtml
innerjoin
input
input readonly
input 属性
inputstream
inputtype
input属性
insert
insert into
insert into select
insertbefore
insertinto
insert语句
inspect
instance
instant
instr