Java的CGLIB动态代理深入解析

 更新时间:2023年11月27日 09:53:54   作者:一码评川  
这篇文章主要介绍了Java的CGLIB动态代理深入解析,CGLIB是强大的、高性能的代码生成库,被广泛应用于AOP框架,它底层使用ASM来操作字节码生成新的类,为对象引入间接级别,以控制对象的访问,需要的朋友可以参考下

一、介绍

CGLIB是强大的、高性能的代码生成库,被广泛应用于AOP框架,它底层使用ASM来操作字节码生成新的类,为对象引入间接级别,以控制对象的访问。

CGLIB相比于JDK动态代理更加强大,JDK动态代理只能对接口进行代理,而CGLIB既可以代理普通类,也能够代理接口。

优点: 通过FastClass机制调用方法,比JDK动态代理的反射机制效率高;被代理类无需实现接口

缺点: 运行期生成字节码,通过ASM写Class字节码,效率低;不能对final类及final方法进行代理

二、工作原理

g

CGLIB 通过动态生成一个需要被代理类的子类(即被代理类作为父类),该子类重写被代理类的所有不是 final 修饰的方法,并在子类中采用方法拦截的技术拦截父类所有的方法调用,进而织入横切逻辑。此外,因为 CGLIB 采用整型变量建立了方法索引,这比使用 JDK 动态代理更快(使用 Java 反射技术创建代理类的实例)。

2.1步骤说明

生成代理对象 创建要被代理的类或接口–MyFly

public class MyFly implements Fly {
    @Override
    public void doFly() {
        System.out.println("wo的");
    }
}

实现MethodInterceptor并实现intercept方法 --CglibProxy

class CglibProxy implements MethodInterceptor {
    /**
     * @param o:           代理对象
     * @param method:      被代理方法
     * @param params:      方法入参
     * @param methodProxy: CGLIB方法
     **/
    @Override
    public Object intercept(Object o, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
        System.out.println("【增强方法】代理对象正在执行的方法:" + method.getName());
        Object result = methodProxy.invokeSuper(o, params);
        return result;
    }
}

创建Enhancer(设置要被代理的类和调用方法时触发的拦截器)

 public static Object creatCglibProxyObj(Class<?> clazz) {
        Enhancer enhancer = new Enhancer();
        // 为加强器指定要代理的业务类(即为下面生成的代理类指定父类)
        enhancer.setSuperclass(clazz);
        // 设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法
        enhancer.setCallback(new CglibProxy());
        return enhancer.create();
    }

执行程序

public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
        Fly fly = (Fly) CglibProxyFactory.creatCglibProxyObj(MyFly.class);
        fly.doFly();
    }

结果:

在这里插入图片描述

2.2 代理对象分析

通过设置属性来输出生成的代理对象

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");

在这里插入图片描述

通过IDEA打开class文件

2.2.1表头分析

在这里插入图片描述

结论: 生成的代理对象继承了我们需要被代理的对象同时实现了Factory这里是通过继承的方式来代理的,所以他即可以代理类也可以代理接口因为是继承了被代理类,所以在java中子类是无法重写父类final方法的,这也就解释了为什么CGLIB无法代理final修饰的方法了

2.2.2 stataic 静态代码块

在这里插入图片描述

结论: 这里面创建了一些后续要试用的变量引用

2.2.3 重写父类方法

在这里插入图片描述

结论: 重写的方法被final,防止后面被修改这里的var10000就是我们在创建代理时传入的CglibProxy这里也就解释了CGLIB是如何动态增强方法的基本逻辑(在每次调用方法时都会先去调用MethodInterceptor的实现类中的intercept方法,然后我们只需要在intercept方法中实现要加强的代码即可)

2.3 代理方法调用过程分析

调用代理方法

在这里插入图片描述

结论: 创建代理对象fly通过调用代理对象fly.doFly()方法

在这里插入图片描述

3. 调用MethodInterceptor的intercept方法,这里就是调用我们的CglibProxy

在这里插入图片描述

4. 调用methodProxy.invokeSuper(o, params);这里就是要调用被代理类的原始方法

在这里插入图片描述

通过init()来初始化生成代理类和被代理类的FastClass

在这里插入图片描述

helper:

在这里插入图片描述

生成的FastClass文件

在这里插入图片描述

生成的FastClass文件的invoke方法

在这里插入图片描述

init完成后这里会继续调用fci.f2.invoke(fci.i2, obj, args); 这里的fci.f2就是刚刚生成的代理对象FastCalss对象

在这里插入图片描述

这里程序会传入17,调用代理类的CGLIB$doFly$0()方法;(大家可以debug看,每次生成的文件位置会不一样)

在这里插入图片描述

调用代理类的CGLIB$doFly$0() 到这里基本可以知道它是如何帮助我们调用被代理类的方法了这里的super指的就是MyFly,因为CGLIB生成的代理类继承了我们要被代理的类

在这里插入图片描述

到此这篇关于Java的CGLIB动态代理深入解析的文章就介绍到这了,更多相关CGLIB动态代理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于BufferedReader的读取效率问题

    关于BufferedReader的读取效率问题

    这篇文章主要介绍了关于BufferedReader的读取效率问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • JAVA基础快速从入门到精通

    JAVA基础快速从入门到精通

    Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征
    2022-03-03
  • Java递归遍历文件目录代码实例

    Java递归遍历文件目录代码实例

    这篇文章主要介绍了Java递归遍历文件目录代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • 如何修改logback.xml配置文件在resource以外的位置

    如何修改logback.xml配置文件在resource以外的位置

    这篇文章主要介绍了如何修改logback.xml配置文件在resource以外的位置,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • JavaCV 拉流存储到本地示例解析

    JavaCV 拉流存储到本地示例解析

    这篇文章主要介绍了JavaCV 拉流存储到本地示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • java ArrayList的深拷贝与浅拷贝问题

    java ArrayList的深拷贝与浅拷贝问题

    这篇文章主要介绍了java ArrayList的深拷贝与浅拷贝问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • 浅谈Timer和TimerTask与线程的关系

    浅谈Timer和TimerTask与线程的关系

    下面小编就为大家带来一篇浅谈Timer和TimerTask与线程的关系。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • 从Java到Kotlin语法平滑迁移实践指南(含详细代码)

    从Java到Kotlin语法平滑迁移实践指南(含详细代码)

    Kotlin作为一门现代编程语言,凭借其简洁的语法、强大的功能和与Java的无缝互操作性,已成为Android开发的首选语言,这篇文章主要介绍了从Java到Kotlin语法平滑迁移的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-05-05
  • Java中@JSONField注解的使用详解

    Java中@JSONField注解的使用详解

    这篇文章主要介绍了Java中@JSONField注解的使用,@JSONField是阿里巴巴开源的JSON处理库FastJSON提供的一个注解,用于在Java对象和JSON数据之间进行序列化和反序列化时,对字段的行为进行更精细的控制,需要的朋友可以参考下
    2025-05-05
  • java中isEmpty和isBlank的区别小结

    java中isEmpty和isBlank的区别小结

    Java中的isEmpty和isBlank都是用来判断字符串是否为空的方法,但在不同的情况下有所区别,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09

最新评论