Java编程使用CGLIB动态代理介绍与实战演示
文章目录
- 前言
- 技术积累
- 核心概念
- 主要功能
- 适用场景
- 与JDK动态代理的对比
- 实战演示
- 定义待代理的目标类
- 实现MethodInterceptor接口
- 使用代理对象
- 测试结果
- 写在最后
前言
在Java编程中,CGLIB (Code Generation Library) 是一个强大的高性能代码生成库,它通过生成被代理类的子类来实现代理功能。相比于JDK动态代理要求目标对象必须实现接口,CGLIB代理适用于那些没有实现任何接口的类。其实动态代理在编码中有很多的使用场景,如方法拦截、权限检查、事务管理、日志记录等等。今天我们就简单分享一期用CGLIB动态代理来扩展类功能。
技术积累
核心概念
- 动态代理: 动态代理是一种设计模式,允许在运行时创建一个对象,该对象可以充当其他对象(目标对象)的代理,从而控制对目标对象方法的访问。代理对象在转发请求到目标对象的同时,可以附加额外的行为,如方法拦截、权限检查、事务管理、日志记录等。
- 字节码操作: CGLIB基于底层的字节码操作技术,利用ASM库动态生成新的Java类(通常是目标类的子类)。这些新生成的类继承自目标类,并在方法调用时插入代理逻辑。这种机制使得CGLIB能够在不修改原有类代码的情况下,为其提供增强功能
主要功能
- 方法拦截: CGLIB的核心功能是实现方法级别的拦截。通过实现MethodInterceptor接口,开发者可以定义一个方法拦截器,该拦截器会在代理对象的方法调用前后执行自定义逻辑,如预处理、后处理、异常处理、结果修饰等。
- 非接口代理: 与JDK动态代理依赖接口不同,CGLIB可以直接对未实现任何接口的普通Java类进行代理。这意味着无论目标类是否声明了接口,都可以使用CGLIB进行代理,极大地拓宽了其适用范围。
- 性能优化: 虽然字节码操作会带来一定的开销,但CGLIB通过高效地生成和缓存代理类,确保了在大多数情况下具有良好的性能。尤其对于频繁创建和销毁代理对象的场景,CGLIB的单例模式表现往往优于JDK动态代理。
适用场景
- AOP框架: 面向切面编程(Aspect-Oriented Programming, AOP)常借助CGLIB来实现方法拦截和织入切面逻辑。Spring框架在内部就集成了CGLIB,用于当目标对象未实现接口时的代理实现。
- 服务端框架: 在某些服务端开发框架(如Hibernate、MyBatis等)中,CGLIB被用来创建持久化对象的代理,以透明地支持延迟加载、变更检测等功能。
- 测试工具: 在单元测试或集成测试中,CGLIB可用于模拟复杂的对象交互,为测试提供灵活的隔离环境。
与JDK动态代理的对比
尽管两者都服务于动态代理需求,但CGLIB与JDK动态代理有明显的差异:
- 代理方式:
JDK动态代理基于接口,创建代理对象时需要目标对象实现至少一个接口。代理对象是接口的实现类,通过反射调用接口方法。
CGLIB代理基于子类,能够代理未实现接口的类。代理对象是目标类的子类,通过继承和方法覆写实现拦截。 - 性能考量:
对于仅需代理接口方法且创建代理对象频率较低的场景,JDK动态代理通常拥有更好的性能,因为它不需要生成额外的类文件,也不涉及字节码操作。
在需要代理非接口类或频繁创建销毁代理对象的情况下,CGLIB由于其高效的字节码生成和缓存策略,可能会表现出更优的性能。 - 应用限制:
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();}@Overridepublic 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也可,这样才能达到事半功倍的效果。
相关文章:
Java编程使用CGLIB动态代理介绍与实战演示
文章目录 前言技术积累核心概念主要功能适用场景与JDK动态代理的对比 实战演示定义待代理的目标类实现MethodInterceptor接口使用代理对象 测试结果写在最后 前言 在Java编程中,CGLIB (Code Generation Library) 是一个强大的高性能代码生成库,它通过生…...
vue3 渲染一个后端返回的图片字段渲染、table表格内放置图片
一、后端直接返回图片url 当图片字段接口直接返回的是图片url,可以直接放到img标签上 <img v-if"thumbLoader" class"r-image-loader-thumb" :src"resUrl" /> 二、当图片字段接口直接返回的是图片Id 那么就需要去拼一下图片…...
iOS开发进阶(十三):脚手架创建iOS项目
文章目录 一、前言二、xcode-select 命令三、拓展阅读 一、前言 项目初期,需要搭建项目基本框架,为此离不开辅助工具,即脚手架。当然,IDE也可以实现新建空白项目,但是其新建后的项目结构可能不符合预期设计࿰…...
手机无线投屏到windows11电脑
1 安装无线投影组件 2 电脑端打开允许其他设备投影的开关 3 手机找到投屏选项 4 手机搜索可用设备连接即可 这里的官方文档给的不太好,给了一些让人眼花撩乱的信息,以下是经过整合的有效信息...
linux 环境安装配置
安装java17 1.下载安装包 wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz 2.解压到自定义目录/usr/local/java mkdir /usr/local/java tar zxvf jdk-17_linux-x64_bin.tar.gz -C /usr/local/java 3.配置环境变量 echo export PATH$PATH:/…...
Git常用语句
设置用户名 git config --global user.name "用户名" git config --global user.email "邮箱"查看git用户信息 cat ~/.gitconfig初始化本地库 git initclone指定分支的代码 git clone -b my_branch gitgitlabxxxxxxxxxxxxxxxxxxxxxx.gitpush三件套 gi…...
坦克大战_java源码_swing界面_带毕业论文
一. 演示视频 坦克大战_java源码_swing界面_带毕业论文 二. 实现步骤 完整项目获取 https://githubs.xyz/y22.html 部分截图 启动类是 TankClinet.java,内置碰撞检测算法,线程,安全集合,一切皆对象思想等,是java进阶…...
JVM 记录
记录 工具 https://gceasy.io 资料 尚硅谷宋红康JVM全套教程(详解java虚拟机) https://www.bilibili.com/video/BV1PJ411n7xZ?p361 全套课程分为《内存与垃圾回收篇》《字节码与类的加载篇》《性能监控与调优篇》三个篇章。 上篇《内存与垃圾回收篇…...
Linux学习笔记————C 语言版 LED 灯实验
这里写目录标题 一、实验程序编写二、 汇编部分实验程序编写三、C 语言部分实验程序编写四、编译下载验证 汇编 LED 灯实验中,我们讲解了如何使用汇编来编写 LED 灯驱动,实际工作中是很少用到汇编去写嵌入式驱动的,毕竟汇编太难,而…...
Spring Boot 配置文件
1. 配置文件的作用 配置文件主要是为了解决硬件编码带来的问题,把可能会发生改变的信息,放在一个集中的地方,当我们启动某个程序时,程序从配置文件中读取一些数据,并加载运行。 硬编码是将数据直接放在源代码中&…...
IPKISS ------ 查看器件默认端口名称
IPKISS ------ 查看器件默认端口名称 正文正文 我们这里以 Grating Coupler 举例。 import si_fab.all as pdk import ipkiss3.all as i3class MyGratingCoupler(i3.circuit):gc = i3.childcellProperty(<...
uni-app踩坑记录
uni-app踩坑记录 Failed to load local image resource xxx the server responded with a status of 500 (HTTP/1.1 500 Internal Server Error) Failed to load local image resource xxx the server responded with a status of 500 (HTTP/1.1 500 Internal Server Error) 文…...
【嵌入式硬件】光耦
1.光耦作用 光耦一般用于信号的隔离。当两个电路的电源参考点不相关时,使用光耦可以保证在两边不共地的情况下,完成信号的传输。 2.光耦原理 光耦的原理图如下所示,其内部可以看做一个特殊的“三极管”; 一般的三极管是通过基极B和发射极E间的电流,去控制集电极C和发射极…...
学习Fast-LIO系列代码中相关概念理解
目录 一、流形和流形空间(姿态) 1.1 定义 1.2 为什么要有流形? 1.3 流形要满足什么性质? (1) 拓扑同胚 (2) 可微结构 1.4 欧式空间和流形空间的区别和联系? (1) 区别: (2) 联系: 1.5 将姿态定义在流形上比…...
React 掌握及对比常用的8个Hooks,优化及使用场景
1、useState 在函数组件中,可以使用useState来定义函数组件的状态。使用useState来创建状态。 1.引入2.接收一个参数作为初始值3.返回一个数组,第一个值为状态,第二个值为改变状态的函数 2、 useEffect useEffect又称副作用hooks。作用&…...
DNS域名解析过程
在互联网中我们通信目标是对方的IP,但是由于IP不便于记忆所以引入了域名 域名和IP是一一对应的关系,需要注意的是域名和网址是不同的概念 比如:www.csdn.net是域名,https://www.csdn.net/?spm1001.2101.3001.4476是网址 首先了解…...
MySQL数据库(数据库连接池)
文章目录 1.批处理应用1.基本介绍2.批处理演示1.创建测试表2.修改url3.编写java代码 3.批处理源码分析 2.数据库连接池1.传统连接弊端分析2.数据库连接池基本介绍1.概念介绍2.数据库连接池示意图3.数据库连接池种类 3.C3P0连接池1.环境配置1.导入jar包2.将整个lib添加到项目中3…...
【C#】知识点速通
前言: 笔者是跟着哔站课程(Trigger)学习unity才去学习的C#,并且C语言功底尚存,所以只是简单地跟着课程将unity所用的C#语言的关键部分进行了了解,然后在后期unity学习过程中加以深度学习。如需完善的C#知识…...
FTP协议
FTP协议 客户端向服务器发送文件。 C/S架构。 运行在TCP/IP协议上面。 FTP客户端要和FTP服务端建立两个TCP连接。 控制连接:运行在整个连接过程,传输控制信息。 数据连接:在每次文件传输时才会建立,文件传输完就关闭。 主动模式…...
前后端分离开发【Yapi平台】【Swagger注解自动生成接口文档平台】
前后端分离开发 介绍开发流程Yapi(api接口文档编写平台)介绍 Swagger使用方式1). 导入knife4j的maven坐标2). 导入knife4j相关配置类3). 设置静态资源映射4). 在LoginCheckFilter中设置不需要处理的请求路径 查看接口文档常用注解注解介绍 当前项目中&am…...
Android的硬件接口HAL-2 HIDL
没写完哈。 不说废话,直接上干活。 1 创建HAL mkdir -p vendor/fanged/hidltest/1.0/defaultvi vendor/fanged/hidltest/1.0/Ilovefanged.hal package vendor.fanged.hardware.hidltest1.0;interface Ilovefanged {add(int32_t a, int32_t b) generates (int32_t…...
pygame--坦克大战(二)
加载敌方坦克 敌方坦克的方向是随机的,使用随机数生成。 初始化敌方坦克。 class EnemyTank(Tank):def __init__(self,left,top,speed):self.images = {U: pygame.image.load(img/enemy1U.gif),D: pygame.image.load(img/enemy1D.gif),L: pygame.image.load(img/enemy1L.gi…...
【C语言】标准输入/输出(printf, scanf, gets, puts, getchar, putchar)
标准文件文件指针设备标准输入stdin键盘标准输出stdout屏幕标准错误stderr您的屏幕 标准输入/输出的函数在标准库stdio.h。 #include <stdio.h> 1、printf 输出 printf :格式化输出,输出到标准输出stdout中。 printf: int print…...
C、C++、C#中.vscode下json文件记录
C launch.json {// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid830387"version": "0.2.0","configurations": [{"name": &quo…...
2013年认证杯SPSSPRO杯数学建模B题(第二阶段)流行音乐发展简史全过程文档及程序
2013年认证杯SPSSPRO杯数学建模 B题 流行音乐发展简史 原题再现: 随着互联网的发展,流行音乐的主要传播媒介从传统的电台和唱片逐渐过渡到网络下载和网络电台等。网络电台需要根据收听者的已知喜好,自动推荐并播放其它音乐。由于每个人喜好…...
使用ARCore深度API实现点云采集
一、深度API 本小节内容摘自ARCore官方文档。 ARCore 深度API Depth API 可助力实现对象遮挡、提升沉浸感和新颖的互动体验,从而增强 AR 体验的真实感。 在下图中,右侧画面是采用深度API进行遮挡后的效果,与左侧图相比更加真实。 深度值 给…...
软考数据库
目录 分值分布1. 事务管理1.1 事物的基本概念1.2 数据库的并发控制1.2.1 事务调度概念1.2.2 并发操作带来的问题1.2.3 并发控制技术1.2.4 隔离级别: 1.3 数据库的备份和恢复1.3.1 故障种类1.3.2 备份方法1.3.3 日志文件1.3.4 恢复 2. SQL语言发权限收权限视图触发器…...
Echarts 自适应宽高,或指定宽高进行自适应
文章目录 需求分析 需求 有一个按钮实现对Echarts的指定缩放与拉长,形成自适应效果 拉长后效果图 该块元素缩短后效果图 分析 因为我习惯使用 ref 来获取组件的 DOM 元素,然后进行挂载 <div ref"echartsRef" id"myDiv" :sty…...
体验报告:为什么Claude-3是码农和学者的新宠?
在这个充斥着海量信息的新时代,人工智能的飞速发展带来了翻天覆地的变化。特别是在编程、学术探索以及专业文案创作等领域,AI的助力显得格外关键。最近,我有机会尝试了一种革命性的人工智能工具——Claude-3,其表现令我震惊&#…...
接口自动化框架搭建(九):接入钉钉消息通知
1,jenkins安装钉钉插件 2,在钉钉群聊设置机器人 3,jenkins配置钉钉 根据情况选择: 除了这些,其他不用配置,配置完成点击确认 4,项目配置 添加后保存 5,测试下效果 构建完成后&a…...
新网站怎么做网络推广/全球搜效果怎么样
虽然opencv3是基于opencv2进行开发的(一部分opencv2代码在opencv3中还能正常运行),但opencv3自身也做了部分修改,而目前网上很多教程还是基于opencv2的函数API来编写的,这导致在使用opencv3时会遇到各种函数未定义之类…...
百度免费域名注册网站/国内新闻最新消息10条
早晨起床时间:7:05 晚上休息时间:23:51 全天处理事件:1.返回厂里,准备明天复工。2.回到宿舍后整理房间内务。 3.采购生活用品。 处事经验总结:暂无。 人生感悟:学会真诚。 其它:明天就要正式复工…...
青岛seo整站优化公司/seo推广人员
我是以Python开门的,我还是觉得Python也可以进行地形三维可视化,当然这里需要借助第三方库,so,我就来介绍:Python一个很重要可视化插件,Matplotlib。 Matplotlib是Python最著名的绘图库,它提供了…...
公司网站推广怎么做/如何用模板建站
今天开始,收集linux下的一些实用命令和操作。1.从命令行切换到图形界面,如果未启动图形界面,先使用startx命令;如果已经启动,则直接crtlaltF7;如果想从图形界面切换到命令行,ctrlaltF1或者其他&…...
wordpress 加载中动画/百度查询入口
查询处理指从数据库中提取数据时涉及的一系列活动, 将用高层数据库语言表示的查询语句翻译为能在文件系统的物理层上使用的表达式 为优化查询而进行各种转换 查询实际执行概述 SQL查询语句->关系代数表达式/语法分析树-…...
大连做网站建设/免费行情网站
div是块级元素,它不论大小默认占一行,而且可以设置宽高以及外边距span是行内元素,它占它自身大小的位置,而且不能设置宽高以及边距同时div也可以变为span (display:inline),这样div将变为行内元素span也可以变为div(display:block…...