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

  Proxy.newProxyInstance(classLoader, interfaces, InvocationHandler)

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

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

  加入执行参数:

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

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

  1. package demo;
  2.  
  3. import java.lang.reflect.InvocationHandler;
  4. import java.lang.reflect.Method;
  5. import java.lang.reflect.Proxy;
  6. import java.lang.reflect.UndeclaredThrowableException;
  7.  
  8. public final class $Proxy0 extends Proxy implements IA {
  9. private static Method m1;
  10. private static Method m4;
  11. private static Method m3;
  12. private static Method m0;
  13. private static Method m2;
  14.  
  15. public $Proxy0(InvocationHandler paramInvocationHandler) {
  16. super(paramInvocationHandler);
  17. }
  18.  
  19. public final boolean equals(Object paramObject) {
  20. try {
  21. return ((Boolean) this.h.invoke(this, m1,
  22. new Object[] { paramObject })).booleanValue();
  23. } catch (RuntimeException localRuntimeException) {
  24. throw localRuntimeException;
  25. } catch (Throwable localThrowable) {
  26. throw new UndeclaredThrowableException(localThrowable);
  27. }
  28. }
  29.  
  30. public final int b(String paramString) {
  31. try {
  32. return ((Integer) this.h.invoke(this, m4,
  33. new Object[] { paramString })).intValue();
  34. } catch (RuntimeException localRuntimeException) {
  35. throw localRuntimeException;
  36. } catch (Throwable localThrowable) {
  37. throw new UndeclaredThrowableException(localThrowable);
  38. }
  39. }
  40.  
  41. public final void a() {
  42. try {
  43. this.h.invoke(this, m3, null);
  44. return;
  45. } catch (RuntimeException localRuntimeException) {
  46. throw localRuntimeException;
  47. } catch (Throwable localThrowable) {
  48. throw new UndeclaredThrowableException(localThrowable);
  49. }
  50. }
  51.  
  52. public final int hashCode() {
  53. try {
  54. return ((Integer) this.h.invoke(this, m0, null)).intValue();
  55. } catch (RuntimeException localRuntimeException) {
  56. throw localRuntimeException;
  57. } catch (Throwable localThrowable) {
  58. throw new UndeclaredThrowableException(localThrowable);
  59. }
  60. }
  61.  
  62. public final String toString() {
  63. try {
  64. return (String) this.h.invoke(this, m2, null);
  65. } catch (RuntimeException localRuntimeException) {
  66. throw localRuntimeException;
  67. } catch (Throwable localThrowable) {
  68. throw new UndeclaredThrowableException(localThrowable);
  69. }
  70. }
  71.  
  72. static {
  73. try {
  74. m1 = Class.forName("java.lang.Object").getMethod("equals",
  75. new Class[] { Class.forName("java.lang.Object") });
  76. m4 = Class.forName("demo.IA").getMethod("b",
  77. new Class[] { Class.forName("java.lang.String") });
  78. m3 = Class.forName("demo.IA").getMethod("a", new Class[0]);
  79. m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
  80. m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
  81. } catch (NoSuchMethodException localNoSuchMethodException) {
  82. throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
  83. } catch (ClassNotFoundException localClassNotFoundException) {
  84. throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
  85. }
  86. }
  87. }

可以发现所有接口方法的实现都委托给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生成的代码类似这样的

  1. public Object invoke(int paramInt, Object paramObject, Object[] paramArrayOfObject)
  2. throws InvocationTargetException
  3. {
  4. // Byte code:
  5. 0: aload_2
  6. 1: checkcast 159 net/sf/cglib/mytest/A$$EnhancerByCGLIB$$f84d7df
  7. 4: iload_1 //paramInt参数入栈
  8. 5: tableswitch default:+403 -> 408, 0:+131->136..... //通过paramInt也就相当于数组小标志,定位到方法执行的代码段
  9. .....
  10. .....
  11. 148: aload_3
  12. 149: iconst_0
  13. 150: aaload
  14. 151: invokevirtual 166 net/sf/cglib/mytest/A$$EnhancerByCGLIB$$f84d7df:equals (Ljava/lang/Object;)Z //直接快速的执行方法
  15. .....
  16. .....
  17.   }
  18. }
    http://www.cnblogs.com/onlywujun/p/3524690.html

jdk和cglib简单理解(转)的更多相关文章

  1. jdk和cglib简单理解

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

  2. Spring AOP中的JDK和CGLib动态代理哪个效率更高?

    一.背景 今天有小伙伴面试的时候被问到:Spring AOP中JDK 和 CGLib动态代理哪个效率更高? 二.基本概念 首先,我们知道Spring AOP的底层实现有两种方式:一种是JDK动态代理, ...

  3. JDK动态代理深入理解分析并手写简易JDK动态代理(下)

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-05/27.html 作者:夜月归途 出处:http://www.guitu ...

  4. JDK动态代理深入理解分析并手写简易JDK动态代理(上)

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-03/27.html 作者:夜月归途 出处:http://www.guitu ...

  5. 【Spring】AOP的代理默认是Jdk还是Cglib?

    菜瓜:你觉得AOP是啥 水稻:我觉得吧,AOP是对OOP的补充.通常情况下,OOP代码专注功能的实现,所谓面向切面编程,大多数时候是对某一类对象的方法或者功能进行增强或者抽象 菜瓜:我看你这个理解就挺 ...

  6. java的静态代理和动态代理(jdk、cglib)

    一.代理模式 代理的概念来自于设计模式中的代理模式,先了解一下代理模式 1.结构图 2.参与者 Subject:接口,定义代理类和实际类的共用接口 RealSubject:实际类,实现Subject这 ...

  7. JDK、CGlib动态代理详解

    Java动态代理之JDK实现和CGlib实现(简单易懂)      一 JDK和CGLIB动态代理原理 1.JDK动态代理 利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生 ...

  8. java设计模式(一)动态代理模式,JDK与CGLIB分析

    -本想着这个知识点放到Spring Aop说说可能更合适一点,但因为上一篇有所提到就简单分析下,不足之处请多多评论留言,相互学习,有所提高才是关键! 什么是代理模式: 记得有本24种设计模式的书讲到代 ...

  9. 关于RabbitMQ的简单理解

    说明:想要理解RabbitMQ,需要先理解MQ是什么?能做什么?然后根据基础知识去理解RabbitMQ是什么.提供了什么功能. 一.MQ的简单理解 1. 什么是MQ? 消息队列(Message Que ...

随机推荐

  1. linux 经常使用配置

    教研室用的非常旧的fedora14,装一些软件和下载东西的时候比較蛋疼,恰巧ubuntu14.04 公布,于是安装试试,顺便记录下经常使用的配置,备忘. 1. 制作镜像,比較老的主板,写入方式选择US ...

  2. C++程序代写实现HashSet class

    C++程序代写实现HashSet class 专业程序代写(QQ:928900200) Implement a HashSet class for elements of type string.It ...

  3. 深度分析 Java 的 ClassLoader 机制(源码级别)(转)

    写在前面:Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中,JVM在加载类的时候,都是通过ClassLoa ...

  4. Git使用总结-so easy

    一.Git的特性 Speed 速度(git是用c语言写的.一般都是提交到本地) Simple design Strong support for non-linear development (tho ...

  5. Windows Phone – 裁剪图片 (Crop Image)

    原文:Windows Phone – 裁剪图片 (Crop Image) 最近在处理图像的功能,对於图像的比例我也不是非常的清楚,因此,在编辑图片上花了不少时间. 该篇文章主要说明的是:如何对图片选择 ...

  6. 如何将IPhone应用软件发布到App Store的

    转自:http://www.shtion.com/667.html 怎样将IPhone应用程序软件公布到应用程序商店? 2009年10月19日公布 分类: App store, iphone, 手机应 ...

  7. Linux:闪光的宝石,智慧 (在)

    Linux:闪光的宝石,智慧的结晶(上) 老实说,这十几天以来.因为我违反了"家规",又被断网处罚(拔掉网线).没收手机与老年证(不许出家门). 因此.我平日里仅仅能面对一篇文章& ...

  8. Gradle入门系列(转)

    Gradle是一种构建工具,它抛弃了基于XML的构建脚本,取而代之的是采用一种基于Groovy的内部领域特定语言.近期,Gradle获得了极大的关注,这也是我决定去研究Gradle的原因. 这篇文章是 ...

  9. android对app代码混淆

    接到新任务.现有项目的代码混淆.在此之前混淆了一些理解,但还不够具体和全面,我知道有些东西混起来相当棘手. 但幸运的是,现在这个项目是不是太复杂(对于这有些混乱).提前完成--这是总结. 第一部分 介 ...

  10. 采用truelicense进行Java规划license控制 扩展可以验证后,license 开始结束日期,验证绑定一个给定的mac住址

    采用truelicense进行Java规划license控制 扩展可以验证后,license 开始结束日期,验证绑定一个给定的mac住址. Truelicense 它是一个开源java license ...