• JDK 动态代理实现与原理

首先来看一段CGLib代理的测试代码(MethodInterceptor的测试, 其他类型这里不做展开了). Util类的代码在后面给出的码云片段中

public 

下面的输出结果除了测试动态代理生效结果外, 还将动态代理生成的类名也输出出来了. 这些类名信息, 在后面的分析中会用到.

Current Pid is:54801
co/wangming/cglib/methodinterceptor/MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
proxy start : class net.sf.cglib.proxy.MethodProxy: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
*****************CreateInfo***********************
Proxy Class: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$printHi$0$Proxy CreateInfo : class net.sf.cglib.proxy.MethodProxy$CreateInfo
CGLIB$printHi$0$Proxy CreateInfo c1: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A
CGLIB$printHi$0$Proxy CreateInfo c2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$equals$1$Proxy CreateInfo : class net.sf.cglib.proxy.MethodProxy$CreateInfo
CGLIB$equals$1$Proxy CreateInfo c1: class java.lang.Object
CGLIB$equals$1$Proxy CreateInfo c2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$toString$2$Proxy CreateInfo : class net.sf.cglib.proxy.MethodProxy$CreateInfo
CGLIB$toString$2$Proxy CreateInfo c1: class java.lang.Object
CGLIB$toString$2$Proxy CreateInfo c2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$hashCode$3$Proxy CreateInfo : class net.sf.cglib.proxy.MethodProxy$CreateInfo
CGLIB$hashCode$3$Proxy CreateInfo c1: class java.lang.Object
CGLIB$hashCode$3$Proxy CreateInfo c2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$clone$4$Proxy CreateInfo : class net.sf.cglib.proxy.MethodProxy$CreateInfo
CGLIB$clone$4$Proxy CreateInfo c1: class java.lang.Object
CGLIB$clone$4$Proxy CreateInfo c2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
*****************CreateInfo***********************
hi
proxy over
hi
*****************FastClassInfo***********************
Proxy Class: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$printHi$0$Proxy FastClassInfo : class net.sf.cglib.proxy.MethodProxy$FastClassInfo
CGLIB$printHi$0$Proxy FastClass f1: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$FastClassByCGLIB$$65f2d708
CGLIB$printHi$0$Proxy FastClass f2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc$$FastClassByCGLIB$$19e0f1ba
CGLIB$printHi$0$Proxy FastClass i1: 0
CGLIB$printHi$0$Proxy FastClass i2: 14
---->
---->
---->
---->
****************FastClassInfo************************

由于生成的代理类的代码过于长, 而知乎没有折叠功能, 所以我将这个代码片段放到了码云上面 . A的代理类的名称是: MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc

cglib 动态代理 - 代码片段 - 码云 Gitee.com​gitee.com

从printHi()方法入手, 看看它的代理是怎么实现的.

// 在MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc类内部, 有下面俩个和printHi方法相关的属性

上面简单分析了代理子类的实现, 但是这都不是重点, 真正的魔法在callback里面. demo里面callback是这么写的

enhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> {System.out.println("proxy start : " + proxy.getClass() + ": " + obj.getClass());Object res = proxy.invokeSuper(obj, args);System.out.println("proxy over");return res;
});

proxy参数的类型是MethodProxy类型, MethodProxy有俩个invoke方法:

  • invoke(Object obj, Object[] args): obj参数不能是MethodInterceptor#intercept()方法的第一个参数obj对象, 否则会造成栈溢出
  • invokeSuper(Object obj, Object[] args): obj参数必须是MethodInterceptor#intercept()方法的第一个参数obj对象

在使用MethodInterceptor的时候, 一定要注意上面这俩点, 下面我们就从invoke/invokeSuper方法入手, 分析一下.

由于这一块的源码过多, 我就不一一都贴出来了, 我画了俩张图帮大家理顺一下.

MethodProxy类里面有一个CreateInfo对象. CreateInfo内部有俩个Class对象, 分别是

  • c1: 目标类的Class对象
  • c2: 目标类的强化类的Class对象, 也就是CGLib生成的目标类的代理子类

CGLib会利用CreateInfo对象去构建出FastClassInfo这个对象. 构建过程就是通过CreateInfo的c1/c2去分别构建出FastClassInfo里面的FastClass类型的f1/f2.

也就是说, 真正的是构建了俩个FastClass对象出来. FastClass对象是通过FastClass内部类Generator进行构建的. 而内部类Generator是将构建过程交给了它的父类AbstractClassGenerator#generate()方法的.

AbstractClassGenerator#generate()又是通过其内部类GeneratorStrategy的对象执行了构建. 最终实现构建的是FastClass#Generator()的generateClass()方法, 该方法实例化了一个FastClassEmitter对象, FastClassEmitter对象内部就是通过ASM去构建Class对象的.

invoke/invokeSuper方法实现如下

public 

init()方法如下

private 

针对init()方法的过程可以参考一下下面的时序图

可以看出来, 整个CGLib的核心就在于这个FastClass

abstract 

FastClass是一个抽象类, CGLib在运行时通过FastClass内的Generator这个内部类将其子类动态生成出来, 然后再利用ClassLoader将生成的子类加载进JVM里面去.

其实, CGLib会为我们生成很多个代理类, 不单单是目标类的子类, 例如上文提到的FastClass f1, FastClass f2的子类是不同的.

  • MethodInterceptorTest$A$$FastClassByCGLIB$$65f2d708 : FastClassInfo#f1, MethodProxy的invoke()方法进行调用
  • MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc$$FastClassByCGLIB$$19e0f1ba : FastClassInfo#f2, MethodProxy的invokeSuper()方法进行调用
public 

在刚开始的demo中, 如果进行如下调用, 会发生递归.

eznhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> {System.out.println("proxy start : " + proxy.getClass() + ": " + obj.getClass());Util.printCreateInfo(list.get(0));Object res2 = proxy.invoke(obj, args1); // 注意,这里将invokeSuper()换成了invoke()System.out.println("proxy over");return res2;});

这是因为(FastClassInfo#i1 的值为0, 因此var1为0, 刚开始的运行日志有输出 )

public 

此时的var10000就是obj, 那么流畅就成了又会去调用MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc的printHi()

public 

因此当调用MethodProxy的invoke()方法时, 必须不能是MethodInterceptor#intercept的第一个obj参数.

而invokeSuper就不会有这个问题, FastClassInfo#i2的值为 14,

public 

因此执行的是var10000.CGLIB$printHi$0();这个方法

 final void CGLIB$printHi$0() {super.printHi();}

这是直接调用A的printHi()方法进行调用.

好了, 到这里分析就告一段落, 下次会分析下, cglib是如何利用ASM生成代理类的.

jdk动态代理实例和cglib动态代理实例_CGLib 动态代理 原理解析相关推荐

  1. 使用 cglib_java动态代理(JDK和CGLIB原理解析与使用)

    CGLIB的动态代理 原理 代理为控制要访问的目标对象提供了一种途径.当访问对象时,它引入了一个间接的层.JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理.JDK的动态代理用起 ...

  2. 动态代理proxy与CGLib的区别

    转载自 动态代理proxy与CGLib的区别 昨天被人问及动态代理与CGlib的区别,赶紧回顾一下: 什么是代理? 静态代理与动态代理 静态代理实例 JDK动态代理实例 CGLib 简介 CGLib ...

  3. 设计模式之代理模式、动态代理模式、Cglib代理模式

    代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这里使用到编程中的 ...

  4. Java 动态代理 原理解析

    概要 AOP的拦截功能是由java中的动态代理来实现的.说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常 ...

  5. Android插件化原理解析——Hook机制之动态代理

    使用代理机制进行API Hook进而达到方法增强是框架的常用手段,比如J2EE框架Spring通过动态代理优雅地实现了AOP编程,极大地提升了Web开发效率:同样,插件框架也广泛使用了代理机制来增强系 ...

  6. java动态代理_Java 动态代理 原理解析

    示例 需要代理的接口 public interface IHello {public void sayHello(); } 需要代理的类 public class HelloImpl implemen ...

  7. 动态代理最全详解系列[2]-Proxy生成代理类对象源码分析

      之前我们通过JDK中的Proxy实现了动态代理,Proxy用起来是比较简便的,但理解起来不是那么清晰,是因为我们并没有看见代理类是怎么生成的,代理类怎么调用的被代理类方法,所以下面我们进入源码看一 ...

  8. 动态代理——拦截器——责任链——AOP面向切面编程底层原理详解(迪丽热巴版)

    目录 动态代理模式详解 前言 什么是代理模式 如何进行代理 静态代理 动态代理 JDK动态代理 CGLIB动态代理 拦截器 责任链模式 博客文章版权申明 动态代理模式详解 前言 代理模式是设计模式中非 ...

  9. 动态代理源码分析,实现自己的动态代理

    什么是代理 增强一个对象的功能 买火车票,app就是一个代理,他代理了火车站,小区当中的代售窗口 java当中如何实现代理 java实现的代理的两种办法 代理的名词 代理对象 增强后的对象 目标对象 ...

最新文章

  1. mysql-事务隔离级别
  2. 查理和政策配对工厂——设计一个问卷运算系统的B端到C端
  3. Hystrix面试 - 深入 Hystrix 执行时内部原理
  4. java操作Excel之POI(4)利用POI实现数据的批量导出
  5. f77编程和c语言的区别,在fortran中l用F77编译器编译程序时出现问题?
  6. 百度地图和openlayers融合封装(想法)
  7. 【算法练习】82.重复的DNA序列——哈希表
  8. Modis数据下载与处理(mrt、wget)
  9. 有谁知道千千静听中的波形特效是怎么做的?
  10. python输出课程表
  11. 用 Wwise 和 Unity 制作 DLC 使用 Wwise 文件包(File Package)
  12. Linux (CentOS) 系统下载地址
  13. 【Security】可信网络连接
  14. ZigBee 设置信道、PANID、发射功率
  15. ninja编译方法介绍
  16. ESP8266-01s——无线模块使用
  17. 使用第三方FTP软件进行文件传输的教程
  18. 中国广告灯箱市场现状调查与投资可行性分析报告2022-2028年
  19. oracle卸载crs,卸载ORACLE CRS
  20. R语言如何绘制簇状、堆积、填充柱形图(16)

热门文章

  1. log4j用于读取.xml文件的出现了错误,类加载器.getResource(user.xml).getPath()返回路径空格变成了%20...
  2. Objective-C中的KVC与KVO(上)
  3. 权限执行[Android开发常见问题-4] RunTime.exec()如何以root权限执行多条指令?
  4. JavaScript 中一句话的思索:this是函数在执行时所处的作用域
  5. 汇编语言之寄存器使用(bx,si,di,bp)
  6. 判断CSS与JS是否加载完毕的方法
  7. Sql中的递归问题-思考与建议
  8. 解决Debian 9 iwlwifi固件缺失导致无法连接无线网络的问题
  9. Redis安装异常解决办法
  10. idea中properties配置文件没有代码提示及代码高亮问题解决方案