Java编程使用CGLIB动态代理介绍与实战演示

news2024/10/7 12:29:00

文章目录

    • 前言
    • 技术积累
      • 核心概念
      • 主要功能
      • 适用场景
      • 与JDK动态代理的对比
    • 实战演示
      • 定义待代理的目标类
      • 实现MethodInterceptor接口
      • 使用代理对象
    • 测试结果
    • 写在最后

前言

在Java编程中,CGLIB (Code Generation Library) 是一个强大的高性能代码生成库,它通过生成被代理类的子类来实现代理功能。相比于JDK动态代理要求目标对象必须实现接口,CGLIB代理适用于那些没有实现任何接口的类。其实动态代理在编码中有很多的使用场景,如方法拦截、权限检查、事务管理、日志记录等等。今天我们就简单分享一期用CGLIB动态代理来扩展类功能。

技术积累

核心概念

  1. 动态代理: 动态代理是一种设计模式,允许在运行时创建一个对象,该对象可以充当其他对象(目标对象)的代理,从而控制对目标对象方法的访问。代理对象在转发请求到目标对象的同时,可以附加额外的行为,如方法拦截、权限检查、事务管理、日志记录等。
  2. 字节码操作: CGLIB基于底层的字节码操作技术,利用ASM库动态生成新的Java类(通常是目标类的子类)。这些新生成的类继承自目标类,并在方法调用时插入代理逻辑。这种机制使得CGLIB能够在不修改原有类代码的情况下,为其提供增强功能

主要功能

  1. 方法拦截: CGLIB的核心功能是实现方法级别的拦截。通过实现MethodInterceptor接口,开发者可以定义一个方法拦截器,该拦截器会在代理对象的方法调用前后执行自定义逻辑,如预处理、后处理、异常处理、结果修饰等。
  2. 非接口代理: 与JDK动态代理依赖接口不同,CGLIB可以直接对未实现任何接口的普通Java类进行代理。这意味着无论目标类是否声明了接口,都可以使用CGLIB进行代理,极大地拓宽了其适用范围。
  3. 性能优化: 虽然字节码操作会带来一定的开销,但CGLIB通过高效地生成和缓存代理类,确保了在大多数情况下具有良好的性能。尤其对于频繁创建和销毁代理对象的场景,CGLIB的单例模式表现往往优于JDK动态代理。

适用场景

  1. AOP框架: 面向切面编程(Aspect-Oriented Programming, AOP)常借助CGLIB来实现方法拦截和织入切面逻辑。Spring框架在内部就集成了CGLIB,用于当目标对象未实现接口时的代理实现。
  2. 服务端框架: 在某些服务端开发框架(如Hibernate、MyBatis等)中,CGLIB被用来创建持久化对象的代理,以透明地支持延迟加载、变更检测等功能。
  3. 测试工具: 在单元测试或集成测试中,CGLIB可用于模拟复杂的对象交互,为测试提供灵活的隔离环境。

与JDK动态代理的对比

尽管两者都服务于动态代理需求,但CGLIB与JDK动态代理有明显的差异:

  1. 代理方式:
    JDK动态代理基于接口,创建代理对象时需要目标对象实现至少一个接口。代理对象是接口的实现类,通过反射调用接口方法。
    CGLIB代理基于子类,能够代理未实现接口的类。代理对象是目标类的子类,通过继承和方法覆写实现拦截。
  2. 性能考量:
    对于仅需代理接口方法且创建代理对象频率较低的场景,JDK动态代理通常拥有更好的性能,因为它不需要生成额外的类文件,也不涉及字节码操作。
    在需要代理非接口类或频繁创建销毁代理对象的情况下,CGLIB由于其高效的字节码生成和缓存策略,可能会表现出更优的性能。
  3. 应用限制:
    JDK动态代理由于依赖接口,无法应用于未声明接口的类。同时,对于final类和方法,以及带有final修饰符的成员变量,JDK动态代理无能为力。
    CGLIB理论上可以代理任何非final类,但对于final类、final方法以及构造函数,CGLIB同样无法进行代理。

实战演示

定义待代理的目标类

首先,创建一个不实现任何接口的ActionUserDataServiceImpl 类,它是我们将要进行CGLIB代理的实际业务逻辑实现。

/**
 * ActionUserDataServiceImpl
 * @author senfel
 * @version 1.0
 * @date 2024/4/3 16:11
 */
public class ActionUserDataServiceImpl {
    /**
     * addUser
     * @author senfel
     * @date 2024/4/3 16:36
     * @return void
     */
    public void addUser() {
        System.out.println("实际执行增加用户的操作...");
    }
}

实现MethodInterceptor接口

为了拦截并处理目标方法调用,我们需要实现net.sf.cglib.proxy.MethodInterceptor接口,其中的核心方法是intercept()。在这个方法中,你可以添加额外的逻辑,如前置处理、后置处理、异常处理或完全替换原有的方法行为。

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

/**
 * StudentProxy
 * @author senfel
 * @version 1.0
 * @date 2024/4/3 16:27
 */
public class MyCglibProxy<T> implements MethodInterceptor {

    /**
     * getProxyInstance
     * @author senfel
     * @date 2024/4/3 16:27
     * @return java.lang.Object
     */
    public Object getProxyInstance(Class<T> tClass)  {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(tClass);
        enhancer.setCallback(this); // 设置回调方法为当前类
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开始执行代理逻辑...");
        // 前置处理或其他逻辑
        beforeProxyRun();
        // 调用原始方法(即目标方法)
        Object result = proxy.invokeSuper(obj, args);
        // 后置处理或其他逻辑
        afterProxyRun();
        System.out.println("结束执行增代理逻辑...");
        return result;
    }

    /**
     * beforeProxyRun
     * @author senfel
     * @date 2024/4/3 16:33
     * @return void
     */
    private void beforeProxyRun() {
        System.out.println("代理前:执行一些预处理操作...");
    }

    /**
     * afterProxyRun
     * @author senfel
     * @date 2024/4/3 16:33
     * @return void
     */
    private void afterProxyRun() {
        System.out.println("代理后:执行一些后续处理操作...");
    }
}

使用代理对象

最后,通过代理类的getProxyInstance()方法获取代理对象,并调用其方法以观察代理效果。

import com.example.ccedemo.proxy.MyCglibProxy;
import com.example.ccedemo.service.ActionUserDataServiceImpl;

/**
 * CglibProxyTest
 * @author senfel
 * @version 1.0
 * @date 2024/4/3 16:29
 */
public class CglibProxyTest {

    public static void main(String[] args) {
        MyCglibProxy<ActionUserDataServiceImpl> actionUserDataServiceMyCglibProxy = new MyCglibProxy<>();
        ActionUserDataServiceImpl actionUserDataService = (ActionUserDataServiceImpl)actionUserDataServiceMyCglibProxy.getProxyInstance(ActionUserDataServiceImpl.class);
        actionUserDataService.addUser();
    }
}

测试结果

开始执行代理逻辑…
代理前:执行一些预处理操作…
实际执行增加用户的操作…
代理后:执行一些后续处理操作…
结束执行增代理逻辑…

在这里插入图片描述

写在最后

以上就是一个完整的Java CGLIB动态代理实例。通过这个例子,可以看到我们成功地对ActionUserDataServiceImpl 类进行了代理,代理过程中插入了额外的前后置处理逻辑,而无需修改原有类的代码。在实际使用时,我们应根据项目需求和目标类特性选择合适的代理方案,不仅仅限制于CGLIB,如果有实现接口的类用JDK也可,这样才能达到事半功倍的效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1566113.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python网络爬虫(三):Selenium--以携程酒店为例

1 Selenium简介 Selenium是一个用于网站应用程序自动化的工具&#xff0c;它可以直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。它相当于一个机器人&#xff0c;可以模拟人类在浏览器上的一些行为&#xff0c;比如输入文本、点击、回车等。Selenium支持多种浏览器&…

数据分析之POWER BI Desktop可视化应用案列

在power bi中导入数据 导入前期建好的模型 简单介绍&#xff08;power bi desktop&#xff09; 将右边字段全部展开 各类数据 所作的模型 在excel中是单向的&#xff0c;power bi 中可以是双向的 右键单击----点击属性 选择两个---在两个方向上应用安全筛选器 变为双向的…

wireshark解析grpc/protobuf的方法

1&#xff0c;wireshark需要安装3.20以上 下载地址&#xff1a;https://www.wireshark.org/ 2&#xff0c;如果版本不对&#xff0c;需要卸载&#xff0c;卸载方法&#xff1a; sudo rm -rf /Applications/Wireshark.app sudo rm -rf $HOME/.config/wireshark sudo rm -rf /…

c++|vector使用及模拟实现

目录 一、vector的介绍 二、vector的使用(常用接口) 2.1string类的成员函数 2.1.1构造函数 2.1.2析构函数 2.1.3“”运算符重载函数 2.2 迭代器(iterator) 及 对象的遍历访问 2.2.1iterator 2.2.2 operator[] && at() 2.2.4 back() && front() 2.2…

认识什么是Git

目录 1. 认识Git 1.1. 问题引入 1.2. 概念 1.3. 作用 1.4. 如何学 1.5. Git 安装 1.6. Git配置用户信息 2. Git仓库 2.1. Git 仓库&#xff08;repository&#xff09; 2.2. 创建 2.3. 需求 3. Git的三个区域 3.1. Git 使用时的三个区域 3.2. 工作区的内容&#…

5.动态规划

1.背包问题 (1)0/1背包问题 01背包问题即每个物品只能选1个 考虑第i件物品&#xff0c;当j<w[i]时&#xff0c;f[i][j]f[i-1][j]&#xff0c;当j>w[i]时&#xff0c;此时有两种选择&#xff0c;选择第i件物品和不选第i件物品。此时f[i][j]max(f[i-1][j],f[i-1][j-w[i]]v…

c++20协程详解(一)

前言 本文是c协程第一篇&#xff0c;主要是让大家对协程的定义&#xff0c;以及协程的执行流有一个初步的认识&#xff0c;后面还会出两篇对协程的高阶封装。 在开始正式开始协程之前&#xff0c;请务必记住&#xff0c;c协程 不是挂起当前协程&#xff0c;转而执行其他协程&a…

789. 数的范围 (二分学习)左端大右,右端小左

题目链接https://www.acwing.com/file_system/file/content/whole/index/content/4317/ 当求左端点时&#xff0c;条件是a【mid】大于等于x&#xff0c;并把右端点缩小。 当求右端点时&#xff0c;条件是a【mid】小于等于x&#xff0c;并把左端点扩大。 1.确定一个区间&…

面试复盘1 - 测试相关(实习)

写在前&#xff1a;hello&#xff0c;大家早中晚上好~这里是西西&#xff0c;最近有在准备测试相关的面试&#xff0c;特此开设了新的篇章&#xff0c;针对于面试中的问题来做一下复盘&#xff0c;会把我自己遇到的问题进行整理&#xff0c;除此之外还会进行对一些常见面试题的…

CentOSPython使用openpyxl、pandas读取excel报错

一、openpyxl报错 由于本人在centos7下使用python的openpyxl报错,所以决定使用强大的pandas。 pandas是一个快速、强大、灵活且易于使用的开源数据操作和分析工具,建立在Python语言之上。 pandas是一个广泛使用的数据分析库,它提供了高效的数据结构和数据分析工具。pandas…

new mars3d.layer.HeatLayer({实现动态修改热力图半径

1.使用热力图插件的时候&#xff0c;实现动态修改热力图效果半径 2.直接修改是不可以的&#xff0c;因为这个是热力图本身的参数。 因此我们需要拿到这个热力图对象之后&#xff0c;参考api文档&#xff0c;对整个 heatLayer.heatStyle进行传参修改。 heatStyle地址&#x…

SSL通配符证书怎么选?看这里

通配符证书&#xff0c;作为一种特殊的数字证书类型&#xff0c;以其独特的优势在网络安全领域扮演着重要角色。相较于传统的单一域名证书&#xff0c;通配符证书能够为同一主域名下的所有子域名提供安全保护&#xff0c;显著提升管理效率&#xff0c;简化证书部署流程&#xf…

【深度学习】sdwebui的token_counter,update_token_counter,如何超出77个token的限制?对提示词加权的底层实现

文章目录 前言关于token_counter关于class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing)如何超出77个token的限制&#xff1f;对提示词加权的底层实现Overcoming the 77 token limit in diffusers方法1 手动拼方法2 compel 问询、帮助请看&#xff1a; 前言 …

[已解决] slam_gmapping: undefined symbol: _ZN8GMapping14sampleGaussianEdm问题

之前用的好好的gampping建图功能包&#xff0c;今天突然不能用了&#xff0c;运行报错如下&#xff1a; /opt/ros/noetic/lib/gmapping/slam_gmapping: symbol lookup error: /opt/ros/noetic/lib/gmapping/slam_gmapping: undefined symbol: _ZN8GMapping14sampleGaussianEdm …

首场直播,就在4月11日!

2024年的第一场直播&#xff0c;我们把目光聚焦到“大会员”。 这一次我们想聊聊&#xff0c;当大会员遇上泛零售企业&#xff0c;会产生怎样的“火花”。泛零售企业突破增长压力的机会在哪里&#xff1f;又有哪些挑战必须直面&#xff1f; 本次直播将结合泛零售企业“多业态、…

双机 Cartogtapher 建图文件配置

双机cartogtapher建图 最近在做硕士毕设的最后一个实验&#xff0c;其中涉及到多机建图&#xff0c;经过调研最终采用cartographer建图算法&#xff0c;其中配置多机建图的文件有些麻烦&#xff0c;特此博客以记录 非常感谢我的同门 ”叶少“ 山上的稻草人-CSDN博客的帮助&am…

Chrome 设置在新窗口中打开链接(已登录google账号版)

Chrome的链接默认是在原标签页中打开的&#xff0c;如果要在新窗口中打开&#xff0c;需要自己自行设置&#xff0c;在此&#xff0c;针对已经登录google账号的chrome浏览器怎么进行设置进行说明。 一、点击登录图标->更多设置 二、选择其他设置->在新窗口中打开搜索结果…

Linux上管理文件系统

Linux上管理文件系统 机械硬盘 机械硬盘由多块盘片组成&#xff0c;它们都绕着主轴旋转。每块盘片上下方都有读写磁头悬浮在盘片上下方&#xff0c;它们与盘片的距离极小。在每次读写数据时盘片旋转&#xff0c;读写磁头被磁臂控制着不断的移动来读取其中的数据。 所有的盘片…

一套C#自主版权+应用案例的手麻系统源码

手术麻醉信息管理系统源码&#xff0c;自主版权应用案例的手麻系统源码 手术麻醉信息管理系统包含了患者从预约申请手术到术前、术中、术后的流程控制。手术麻醉信息管理系统主要是由监护设备数据采集子系统和麻醉临床系统两个子部分组成。包括从手术申请到手术分配&#xff0c…

SSM框架学习——JSP语法入门

JSP语法入门 前提 在前一节中我们已经写过JSP的代码了&#xff0c;这一节将单独介绍JSP一些基础语法。当然&#xff0c;你可以跳过这一节&#xff0c;当后面有代码不太理解的时候再回来阅读。 中文编码问题 如果中文乱码&#xff0c;看看JSP是否是以UTF8的方式编码&#xf…