look相关知识
-
我自横刀向天笑,手写Spring IOC容器,快来Look Look!AOP分析 AOP是什么 Aspect Oriented Programming 面向切面编程,在不改变类的代码的情况下,对类的方法进行功能增强 那么如果要实现一个AOP,需要做的事情就是要向使用的用户提供AOP功能,能够通过AOP技术实现对类的方法进行功能增强 AOP中的元素 Advice 通知,即增强的功能 Join points 连接点,可以选择的方法点,即有哪些可以增强的方法供选择 Pointcut 切入点,选择切入的方法点,即对哪些方法进行增强 Aspact 切面,选择的多个方法点 + 增强的功能,即Advice和Pointcut的
-
图书管理系统【部署开发环境、解决分类、图书、前台页面模块】(2)后台显示图书模块 由于我们用的是分页技术,所以我们导入之前写过的Page类和jsp吧.....这些代码可以在我分类的代码库中找到 绑定超链接 <a href="${pageContext.request.contextPath}/BookServlet?method=look" target="body">查看图书</a> Servlet处理请求 else if (method.equals("look")) { String currentPageCount = request.getParameter("currentPageCount"); Page page = service.getPageData(currentPageCount); request.setAttribute("page",page); request.getRe
-
Learning FaceBook Connecthttp://wiki.developers.facebook.com/index.php/Trying_Out_Facebook_ConnectFaceBook Connect is used to quickly integrate your site with Facebook account.I look into http://www.somethingtoputhere.com/therunaround/index.php demo site using FackBook Connect, and come to some results:1. Click “Connect with FaceBook” button, a popup window appears. It’s a page of FaceBook: http://www.connect.facebook.com/login.php2. Login to FaceBook use your account,
-
SAS Box PlotSAS Day 33: Box Plot Definition: Box Plot or Whisker plot displays the distribution of 5-number summary of a dataset: minimum, maximum, q1, q3, and Median. Interpreting quartiles: The 5-number summary approximately divides the data into 4 sections that each containing 25% of the data. Explore a little more If we want to look at the Outliers, we define the points below q1- 1.5(q3-q1) and q3+
look相关课程
look相关教程
- 3. 使用场景和应用实例 加粗和斜体,都是对文字的变形,都是由西方排版规则引入的概念。斜体形态类似于手写,多用于有一定长度的重点文字,比如引用、书籍或人物的名称、夹杂的外语等,多用于英文文档中。粗体多用于强调一个段落中的某些关键词,相比斜体,他的强调作用更强,强调的内容更短,多用于标题。从文字重要性方面理解,斜体的重要性略低于正文,代表对正文的补充;粗体的重要性高于正文,代表对正文内容的提炼。实例 3:一篇英语单词翻译结果页。#### marvel***verb*** [ I ]**uk** /ˈmɑː.vəl/ **us** /ˈmɑːr.vəl/ **-ll-** or US usually **-l-**___【中英文释义】**to show or experience great surprise or admiration** **(对…)感到惊奇,惊叹**【例句】 1. _We paused to **marvel** at the view._ 我们停下来,**感叹**景色**之美**。 2. _[ + that ] I often **marvel** that humans can treat each other so badly._ 我常为人类会如此恶待彼此感到**惊讶**。 3. _[ + speech ] "Just look at that waterfall! Isn't it amazing?" she **marvelled**._ “看那瀑布!真是令人惊叹,不是吗?”她**赞叹道**。其渲染结果如下:
- 使用 TensorBoard 记录训练中的各项指标 在前面的学习中,我们学习到了如何使用 TensorBoard 来记录 Loss 等基本的参数。那么我们可以定义更加复杂的参数指标,以至于可以自定义指标吗?答案是可以的,那么我们这节课便来学习一下如何在 TensorBoard 之中输出更加复杂的指标甚至自定义指标。In the previous tutorial, we learned how to use the TensorBoard to record basic parameters such as Loss. So can we define more complex parameter metrics to the point where we can customize metrics? The answer is yes, so let’s take a look at how to output more complex metrics or even custom metrics in the TensorBoard.自定义指标大致可以分为两种:There are two broad categories of custom metrics:使用回调进行自定义的输出; Custom output using callbacks;在自定义循环中手动添加输出。 Manually add output in a custom loop我们这节课来分别学习以下如何使用两者来进行自定义的输出。In this lesson, we will learn how to use each of the following to customize the output.
- 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 参数就相当于利用反射去调用这个方法。
- 34 Linux 添加用户组 零基础学习,程序员必须要掌握 Linux 操作系统
- Kotlin 类型系统 Kotlin 是安卓开发的官方语言
- 第二章RabbitMQ快速入门回顾 RabbitMQ从入门到进阶,建议随课使用
look相关搜索
-
label
labelfor
label标签
lambda
lambda表达式
lamda
lang
last
latin
latin1
layers
layui
leave
left
leftarrow
legend
length
lengths
length函数
less