转载自 jdk和cglib简单理解

 之前使用cglib的时候不需要将classLoader作为参数传入,但动态代理却要,带着这个疑惑进入这个方法:

  Proxy.newProxyInstance(classLoader, interfaces, InvocationHandler)

  要在classLoader里去找interfaces,如果也加载进来了才能继续执行,并且用ProxyGenerator动态生成了一个代理类的字节码文件(使用了缓存技术,只需要生成一次),然后用classLoader将这个字节码文件加载进来。这就是classLoader的作用。

  可以这样看生成的字节码类。

  加入执行参数:

  System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")

  生成的字节码文件就会保留下来,然后编译出来如下:

package demo;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 IA {private static Method m1;private static Method m4;private static Method m3;private static Method m0;private static Method m2;public $Proxy0(InvocationHandler paramInvocationHandler) {super(paramInvocationHandler);}public final boolean equals(Object paramObject) {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 int b(String paramString) {try {return ((Integer) this.h.invoke(this, m4,new Object[] { paramString })).intValue();} catch (RuntimeException localRuntimeException) {throw localRuntimeException;} catch (Throwable localThrowable) {throw new UndeclaredThrowableException(localThrowable);}}public final void a() {try {this.h.invoke(this, m3, null);return;} catch (RuntimeException localRuntimeException) {throw localRuntimeException;} catch (Throwable localThrowable) {throw new UndeclaredThrowableException(localThrowable);}}public final int hashCode() {try {return ((Integer) this.h.invoke(this, m0, null)).intValue();} catch (RuntimeException localRuntimeException) {throw localRuntimeException;} catch (Throwable localThrowable) {throw new UndeclaredThrowableException(localThrowable);}}public final String toString() {try {return (String) this.h.invoke(this, m2, null);} 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") });m4 = Class.forName("demo.IA").getMethod("b", new Class[] { Class.forName("java.lang.String") });m3 = Class.forName("demo.IA").getMethod("a", new Class[0]);m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);} catch (NoSuchMethodException localNoSuchMethodException) {throw new NoSuchMethodError(localNoSuchMethodException.getMessage());} catch (ClassNotFoundException localClassNotFoundException) {throw new NoClassDefFoundError(localClassNotFoundException.getMessage());}}
}

可以发现所有接口方法的实现都委托给InvocationHandler的invoke方法了,这也就是实现代理模式的地方了。

--------------------------------------------------------------------------

cglib不需要传入ClassLoader,代码里会自己去找上下文的ClassLoader,这种设计使少传一个ClassLoader这种很少见的参数对初学者来说用起来要简单点。

可以设置System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "字节码文件保存位置",把cglib生成的动态字节码保存下来。

单间分析下生成的字节码

动态生成的继承类会改写我们使用的父类的所有方法,拦截下来交给设置的MethodInterceptor去执行。

  public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy)

第一个参数obj就是动态生成的子类。第二个参数是原始类的方法。

  我们一般使用proxy.invokeSuper(obj,args)方法。这个很好理解,就是执行原始类的方法。还有一个方法proxy.invoke(obj,args),这是执行生成子类的方法。如果传入的obj就是子类的话,会发生内存溢出,因为子类的方法不挺地进入intercept方法,而这个方法又去调用子类的方法,两个方法直接循环调用了。

  我们来看看MethodProxy,原始类里每一个方法都会在动态的子类里有一个对应的MethodProxy,而一个MethodProxy又对应了两个动态生成的FastClass类,一个是对应原始方法,一个对应新生成的子类,MethodProxy.invokeSuper就是交给对应原始方法那个FastClass,MethodProxy.invoke交给另一个。

  这2个额外生成的类作用在于当我们调用一个方法时,不通过反射来调用,而是通过类似于数组下标的方式来定位方法,直接进行类方法的执行。

  FastClass生成的代码类似这样的

public Object invoke(int paramInt, Object paramObject, Object[] paramArrayOfObject)throws InvocationTargetException{// Byte code:0: aload_2 1: checkcast 159 net/sf/cglib/mytest/A$$EnhancerByCGLIB$$f84d7df4: iload_1   //paramInt参数入栈5: tableswitch    default:+403 -> 408, 0:+131->136..... //通过paramInt也就相当于数组小标志,定位到方法执行的代码段
.....
.....148: aload_3149: iconst_0150: aaload151: invokevirtual 166 net/sf/cglib/mytest/A$$EnhancerByCGLIB$$f84d7df:equals  (Ljava/lang/Object;)Z //直接快速的执行方法
.....
.....}
}

  

jdk和cglib简单理解相关推荐

  1. JDK 动态代理的简单理解

    http://www.cnblogs.com/luotaoyeah/p/3778183.html JDK 动态代理的简单理解 动态代理 代理模式是 Java 中的常用设计模式,代理类通过调用被代理类的 ...

  2. Spring源码深度解析(郝佳)-学习-jdk代理-cglib代理

    在java中目前主要使用的是jdk代理和cglib代理,这两种代理是Spring AOP的精髓所在,不过在理解Spring AOP之前,先来看看这两种代理的使用. 1. jdk代理使用示例 创建业务接 ...

  3. 字符串匹配算法Java_如何简单理解字符串匹配算法?

    这篇文章来说说如何简单理解KMP,BM算法.之前看过一些文章说,KMP算法很难理解. 可我并不觉得. 我反而觉得它容易理解.平时我们写java代码的时候, 判断一个字符串是否存在包含另一个字符串都是直 ...

  4. Java:java学习笔记之锁机制的简单理解和使用

    锁机制的简单理解和使用 锁机制 1.背景 2.定义 3.锁的种类 4.乐观锁 VS 悲观锁 4.1.悲观锁 4.2.乐观锁 4.3.举例说明 4.4.CAS算法 4.4.1.CAS使用 4.4.2.C ...

  5. android 点击事件消费,Android View事件分发和消费源码简单理解

    Android View事件分发和消费源码简单理解 前言: 开发过程中觉得View事件这块是特别烧脑的,看了好久,才自认为看明白.中间上网查了下singwhatiwanna粉丝的读书笔记,有种茅塞顿开 ...

  6. 【转载】Deep learning:十九(RBM简单理解)

    Deep learning:十九(RBM简单理解) 这篇博客主要用来简单介绍下RBM网络,因为deep learning中的一个重要网络结构DBN就可以由RBM网络叠加而成,所以对RBM的理解有利于我 ...

  7. 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

    2019独角兽企业重金招聘Python工程师标准>>> 在运行时期可以按照Java虚拟机规范对class文件的组织规则生成对应的二进制字节码.当前有很多开源框架可以完成这些功能,如A ...

  8. 学习:双机热备、集群、负载均衡、SQL故障转移群集简单理解(转)

    双机热备.集群.负载均衡.SQL故障转移群集简单理解平常,大家常提到几个技术名词:双机热备.集群.负载均衡.SQL故障转移群集.这里,就我的理解,和大家简单探讨下,有不足或错误之处还请各位指出! 这些 ...

  9. spring框架中JDK和CGLIB动态代理区别

    转载:https://blog.csdn.net/yhl_jxy/article/details/80635012 前言 JDK动态代理实现原理(jdk8):https://blog.csdn.net ...

最新文章

  1. 硬投票分类器(VotingClassifier)构建实战
  2. 插入顶部_声屏障顶部斜插式安装可获得10-25dB的降噪量
  3. Spark On YARN 集群安装部署
  4. 笔记-项目风险管理-风险应对
  5. iOS中常见的内存问题
  6. 单IP无TMG拓扑Lync Server 2013:活动目录
  7. why header level note is disabled
  8. Linux命令(4):开挂机重启
  9. 信息学奥赛一本通(1149:最长单词2)
  10. spring数据字典_Redis为什么默认16个数据库?
  11. 微软中国CTO:手机里装的App一上网基本等于裸奔
  12. 如何用数据找到下一家独角兽?
  13. Python数据分析与可视化期末简答题复习
  14. python怎么算阶乘_Python 计算阶乘的算法
  15. php carbon 格式化,PHP Carbon
  16. 振芯科技GM8285C:功能TTL转LVDS芯片简介
  17. 风控评分卡模型——逻辑回归
  18. HDU 2222(AC自动机模板)
  19. [单调栈/差分/尺取/单调队列]Exercise Week5 A最大矩形+B魔法猫+C平衡字符串+D滑动窗口
  20. 2013百度校园招聘数据挖掘工程师

热门文章

  1. 字符串经典题目(Leetcode题解-Python语言)
  2. 你真的理解事件绑定、事件冒泡和事件委托吗?
  3. [蓝桥杯]回形取数-方向向量+模拟
  4. Stack(栈 c++模版实现)
  5. ios 顶部tab滑动实现_iOS开发之多表视图滑动切换示例(仿头条客户端)
  6. xshell1分钟就会自动断_手术室自动门不能正常控制开关门维修案例
  7. G. GCD Festival(莫比乌斯、欧拉函数)
  8. P2766 最长不下降子序列问题(网络流)
  9. P2487 [SDOI2011]拦截导弹(cdq分治/计数问题思想)
  10. Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4) 构造