CGLib动态代理和JDK动态代理Demo、ASM技术尝鲜
本文主要介绍CGLib和JDK动态代理的使用,不对源码进行深入分析。代码可直接复制使用。
类型 | 机制 | 回调方式 | 适用场景 | 效率 |
JDK动态代理 | 委托机制。代理类和目标类都实现了同样的接口。InvocationHandler持有目标类。代理类委托InvocationHandler去调用目标类原始方法 | 反射 | 目标类实现接口 | 反射调用稍慢。 |
CGLIB动态代理 | 继承机制。代理类继承了目标类并重写了目标方法,通过回调函数MethodInterceptor调用父类方法执行原始逻辑(底层使用到ASM技术,操作字节码生成代理类) | 通过FastClass方法索引调用 | 非final类,非final方法 | 第一次调用因为要生成多个Class对象较]DK慢,但是调用时方法索引较反射方式快 |
代码框架:
类UserInterface
package com.cocoa.dao;public interface UserInterface {public void test();
}
类UserService
package com.cocoa.dao;public class UserService implements UserInterface{@Overridepublic void test() {System.out.println("UserService test() -- print");}
}
类CGLIBDemo
method.invoke()使用的还是反射机制;但是methodProxy.invoke使用的不是反射,而是FastClass机制,通过建立代理类的索引,快速执行代理的方法。(所以比JDK快)
MethodIntercept的入参:
o:目标对象的实例(被代理的对象);
method:被代理的方法;
objects:方法调用时的入参;
methodProxy:用于调用原始方法的代理。
package com.cocoa.enhancer;import com.cocoa.dao.UserService;
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CGLIBDemo {public static void Main(String[] args) {// 动态代理生成的字节码存储到本地System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "com.cocoa.enhancer");final UserService target = new UserService();// 增强器Enhancer enhancer = new Enhancer();// enhancer.setUseCache(false);// 使用缓存// 设置代理的类enhancer.setSuperclass(UserService.class);// 设置代理逻辑enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {if (method.getName().equals("test")){System.out.println("before...");method.invoke(target, objects);System.out.println("after...");}return null;}});// 使用代理类UserService userService = (UserService) enhancer.create();// create会将第一次产生的代理类缓存下来userService.test();}
}
要避免使用method.invoke(),应该使用methodProxy。
类CGLIBDemo1
使用methodProxy.invoke执行方法(通过FastCLass索引机制)
methodProxy.invoke(target, objects);// test() 正常运行,直接执行代理方法
methodProxy.invoke(o, objects);// o 表示代理对象,这样会导致死循环
methodProxy.invokeSuper(target, objects);// CGLIB$test$4() 因为target中没有代理对象的方法
methodProxy.invokeSuper(o, objects);// CGLIB$test$4() 执行代理对象o中的test方法 正常运行
package com.cocoa.enhancer;import com.cocoa.dao.UserService;
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** MethodProxy的使用*/
public class CGLIBDemo1 {public static void main(String[] args) {System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "com.cocoa.enhancer");final UserService target = new UserService();// 增强器Enhancer enhancer = new Enhancer();// enhancer.setUseCache(false);// 使用缓存// 设置代理的类enhancer.setSuperclass(UserService.class);// 设置代理逻辑enhancer.setCallback(new MethodInterceptor() {@Override// o代理对象 objects入参 method被代理的方法 methodProxy代理的方法public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {if (method.getName().equals("test")){System.out.println("before...");// MethodProxy 表示方法代理,代理了两个方法 test()
// methodProxy.invoke(target, objects);// test() 可用
// methodProxy.invoke(o, objects);// o 表示代理对象,这样会导致死循环
// methodProxy.invokeSuper(target, objects);// CGLIB$test$4() 因为target中没有代理对象的方法methodProxy.invokeSuper(o, objects);// CGLIB$test$4() 执行代理对象o中的test方法 可用System.out.println("after...");}return null;}});// 使用代理类UserService userService = (UserService) enhancer.create();// create会将第一次产生的代理类缓存下来userService.test();}
}
类mainInterface
package com.cocoa.enhancer;import com.cocoa.dao.UserInterface;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** CGLIB 可以代理接口*/
public class mainInterface {public static void main(String[] args) {Enhancer enhancer = new Enhancer();// 设置代理的接口enhancer.setSuperclass(UserInterface.class);// 设置代理逻辑enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("切面逻辑...");return null;}});// 使用代理类UserInterface userInterface = (UserInterface) enhancer.create();userInterface.test();}
}
类JDKDemo
使用proxy.newProxyInstance方法直接构造代理类,入参有:
1)真实对象的类加载器;
2)真实对象实现的接口;
3)代理类需要实现InvocationHandler接口,重写Invoke方法。
invoke方法的入参:
参数1:用Proxy.newProxyInstance方法产生的真实对象,注意,参数1并不显式地出现在方法体内;
参数2:要调用的目标方法;
参数3:目标方法中的参数,一般是 Object[ ] args。
package com.cocoa.jdkProxy;import com.cocoa.dao.UserInterface;
import com.cocoa.dao.UserService;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class JDKDemo {public static void main(String[] args) {// Proxy.newproxyInstance// 类加载器、代理的接口、new InvocationHandlerUserService target = new UserService();UserInterface userInterface = (UserInterface) Proxy.newProxyInstance(JDKDemo.class.getClassLoader(), new Class[]{UserInterface.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("test");method.invoke(target, args);return null;}});userInterface.test();}
}
ASM技术尝鲜
通过ASM字节码技术,可以生成一个类。执行下面的代码,就可以生成下图中的类。
package com.cocoa.asmDemo;import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;/*** ASM 尝鲜使用*/
public class ASMDemo {public static void main(String[] args) throws IOException {ClassWriter classWriter = new ClassWriter(0);// 通过visit 方法确定类的头部信息classWriter.visit(Opcodes.V1_8,// java版本Opcodes.ACC_PUBLIC,// 类修饰符"Person", // 类的全限定名null, "java/lang/Object", null );// 创建构造函数MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);mv.visitCode();mv.visitVarInsn(Opcodes.AALOAD, 0);// 字节码指令mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");mv.visitInsn(Opcodes.RETURN);mv.visitMaxs(1,1);mv.visitEnd();// 定义test方法MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "test", "()V", null, null);methodVisitor.visitCode();methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");methodVisitor.visitLdcInsn("hello zhouyu");methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream","println","(Ljava/lang/string;)V");methodVisitor.visitInsn(Opcodes.RETURN);methodVisitor.visitMaxs(2,2);methodVisitor.visitEnd();classWriter.visitEnd();// 使classWriter类已经完成// 将classWriter转换成字节数组写到文件里面大byte[] data =classWriter.toByteArray();File file = new File( "E:\\java_shicao\\DynamicProxyDemo\\src\\main\\java\\People.class");FileOutputStream fout = new FileOutputStream(file);fout.write(data);fout.close();}
}
相关文章:

CGLib动态代理和JDK动态代理Demo、ASM技术尝鲜
本文主要介绍CGLib和JDK动态代理的使用,不对源码进行深入分析。代码可直接复制使用。 类型 机制 回调方式 适用场景 效率 JDK动态代理 委托机制。代理类和目标类都实现了同样的接口。InvocationHandler持有目标类。代理类委托InvocationHandler去调用目标类原…...

[C++]使用纯opencv部署yolov11-pose姿态估计onnx模型
【算法介绍】 使用纯OpenCV部署YOLOv11-Pose姿态估计ONNX模型是一项具有挑战性的任务,因为YOLOv11通常是用PyTorch等深度学习框架实现的,而OpenCV本身并不直接支持加载和运行PyTorch模型。然而,可以通过一些间接的方法来实现这一目标&#x…...

python you-get下载视频
You-Get是一个使用Python开发的命令行工具,用于下载网络上的音视频资源。你可以通过pip安装You-Get,具体操作如下: 打开命令行工具,输入pip install you-get,然后回车执行命令 You-Get还允许你指定下载的视频格式和质…...

SCUC博客摘录「 储能参与电能市场联合出清:SCUC和SCED模型应用于辅助服务调频市场(IEEE39节点系统)」2024年10月6日
2.1 SCUC模型在本方法中,首先利用SCUC模型确定机组出力计划和储能充放电计划。SCUC模型是电力系统经济调度的重要工具,通过优化发电机组出力计划和调度,实现电力系统的经济性和可靠性。在考虑储能的情况下,SCUC模型需要考虑储能的…...

Git分支-团队协作以及GitHub操作
Git分支操作 在版本控制过程中,同时推进多个任务> 程序员开发与开发主线并行,互不影响 分支底层也是指针的引用 hot-fix:相当于若在进行分支合并后程序出现了bug和卡顿等现象,通过热补丁来进行程序的更新,确保程序正常运行 常…...

力扣刷题 | 两数之和
目前主要分为三个专栏,后续还会添加: 专栏如下: C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读! 初来乍到,如有错误请指出,感谢! 给定一个整数数组 nums 和…...

[C#]winform部署官方yolov11-obb旋转框检测的onnx模型
【官方框架地址】 https://github.com/ultralytics/ultralytics 【算法介绍】 Yolov11-obb(You Only Look Once version 8 with Oriented Bounding Boxes)是一种先进的对象检测算法,它在传统的Yolov3和Yolov4基础上进行了优化,加…...

【GC日志和OOM日志分析】JVM GC日志和OOM Dump文件分析
1 缘起 充电、充电、充电。 增加一些必备的知识,帮助后续使用。 2 配置JVM参数 为分析GC日志以及OOM相关信息,配置JVM参数,分为三个部分: (1)堆内存,包括年轻代、最大堆内存; &a…...

【电路】1.1 实际电路和电路模型
1.1 实际电路和电路模型 科学理论的研究对象是现实世界背后的抽象世界,如: 数学中的 ∞ \infty ∞,经典力学中“质点”的概念,牛顿运动定律(如惯性定律,如果一个物体不受外力情况下,一直保持匀…...

Vue - 打包部署
vscode找到NPM脚本,点击build。 目录下出现dist目录则表示安装成功。 安装Nginxnginx: download 目录用途conf配置文件目录html静态资源文件目录logs日志文件目录temp临时文件目录 将刚刚打包好的文件放到html目录下。 点击nginx.exe,用localhost:默认…...

spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理)
文章目录 【README】【1】文件上传与MultipartResolver【1.1】使用MultipartResolver进行文件上传【1.2】springmvc处理multipart多部件请求流程【1.3】使用springmvc上传文件代码实现(springmvc6.10版本): 【2】Handler与HandlerAdaptor&…...

springboot项目中属性的使用优先级;maven编译插件切换环境变量
概述 在项目部署时,相关的生产环境和测试环境是分开的,但是代码是同一套; 所以一般会有多套变量; 项目中默认变量(一般是测试环境) 线上变量(线上数据较敏感,一般也不会放在代码中&…...

【Qt】控件概述 (1)—— Widget属性
控件概述 1. QWidget核心属性1.1核心属性概述1.2 enable1.3 geometry——窗口坐标1.4 window frame的影响1.4 windowTitle——窗口标题1.5 windowIcon——窗口图标1.6 windowOpacity——透明度设置1.7 cursor——光标设置1.8 font——字体设置1.9 toolTip——鼠标悬停提示设置1…...

(笔记)第三期书生·浦语大模型实战营(十一卷王场)–书生基础岛第3关---浦语提示词工程实践
学员闯关手册:https://aicarrier.feishu.cn/wiki/ZcgkwqteZi9s4ZkYr0Gcayg1n1g?open_in_browsertrue 课程视频:https://www.bilibili.com/video/BV1cU411S7iV/ 课程文档: https://github.com/InternLM/Tutorial/tree/camp3/docs/L1/Prompt 关…...

OpenCV视频I/O(11)视频采集类VideoCapture之设置视频捕获设备的属性函数 set()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 VideoCapture 中设置一个属性。 在OpenCV中,cv::VideoCapture::set() 函数用于设置视频捕获设备的属性。这些属性可以包括分辨率、…...

数据结构之树(3)
一、森林和树的转换 重要! 树->二叉树 由于孩子兄弟链式存储和二叉树链式存储本质相同,故树可转换为二叉树。 森林->二叉树 森林:m棵互不相交的树的集合 森林->树 树->二叉树 森林中各个树的根节点之间视为兄弟关系 二、树…...

螺蛳壳里做道场:老破机搭建的私人数据中心---Centos下docker学习02(yum源切换及docker安装配置)
2 前期工作 2.1 切换yum源并更新 删除/etc/yum.repos.d/原有repo文件,将Centos-7.repo库文件拷贝到该目录下。 然后清楚原有缓存yum clean all 生成新的缓存yum makecache 更新yum update –y 然后再确认/etc/yum.repos.d/不会有其他库文件,只留下…...

强化学习笔记之【Q-learning算法和DQN算法】
强化学习笔记(一)——Q-learning和DQN算法核心公式 文章目录 强化学习笔记(一)——Q-learning和DQN算法核心公式前言:Q-learning算法DQN算法 前言: 强化学习领域,繁冗复杂的大段代码里面&#…...

面试经验02
嵌入式简历制作指南与秋招求职建议 引言 秋招季即将到来,许多同学开始准备求职简历。无论你是考研失利准备就业,还是即将毕业寻找实习,一份优秀的简历都是求职的敲门砖。今天,我们将讨论如何制作嵌入式领域的求职简历࿰…...

分层图 的尝试学习 1.0
分层图: 分层图的最短路: 又叫做 扩点最短路。不把实际位置看做是图上的点,而是把实际位置及其状态的组合,(一个点有若干的状态,所以一个点会扩充出来若干点)看做是图上的点,然后搜索…...

第 31 章 javascript 之 XPath
第 31 章 XPath 1.IE 中的 XPath 2.W3C 中的 XPath 3.XPath 跨浏览器兼容 XPath 是一种节点查找手段,对比之前使用标准 DOM 去查找 XML 中的节点方式,大大降低了查找难度,方便开发者使用。但是,DOM3 级以前的标准并没有就 XPa…...

JavaScript中的高阶函数
高阶函数 所谓高阶函数,就是操作函数的函数,它接收一个或多个函数作为参数,并返回一个新函数: 来看一个mapper()函数,将一个数组映射到另一个使用这个函数的数组上: 更常见的例子,它接收两个函…...

Qt6.7开发安卓程序间接连接到MySQL的方法
本文主要描述一种通过间接的方法,使得Qt开发的安卓程序可以直连到Mysql数据库的方法。本文章的方案是通过JAVA代码去连接MySQL数据库,然后C代码去调用JAVA的方法,从而实现QT开发的安卓程序去直连到MySQL数据库。 本文使用 JDBC 结合 JNI&…...

ROW_NUMBER
How to rewrite a query which uses the ROW_NUMBER() window function in versions 5.7 or earlier before window functions were supported e.g., SELECT ROW_NUMBER() OVER (PARTITION BY fieldA) AS rownum, myTable.* FROM myTable; index 用不上的 Solution Assuming…...

Docker技术
目录 Docker的基本概念 Docker的核心原理 Docker的使用场景 Docker的优点 Docker的挑战 为什么使用 环境一致性 快速启动和部署 资源利用率高 支持微服务架构 持续集成与持续交付(CI/CD) 依赖管理 简化部署流程 高效资源管理 生态系统丰富…...

中小企业做网站需要考虑哪些因素?
中小企业在建设网站时,需要考虑的因素有很多。以下是一些主要考虑因素的介绍: 明确建站目的:中小企业需要明确自己建立网站的目的。是为了展示企业形象、推广产品,还是提供客户服务?不同的目的将决定网站的设计和功能…...

【d60】【Java】【力扣】509. 斐波那契数
思路 要做的问题:求F(n), F(n)就等于F(n-1)F(n-2),要把这个F(n-1)F(n-2)当作常量,已经得到的值, 结束条件:如果是第1 第2 个数字的时候,没有n-1和n-2,所以…...

项目-坦克大战学习-游戏结束
当boos受到伤害时游戏结束,游戏结束时我们需要将窗体全部绘制从别的画面,这样我们可以在游戏运行类中的update设置条件,在游戏运行类thread创建一个枚举类型定义是否游戏结束 public enum Game { play, over };//定义现在游戏运行状态 如果…...

MySQL基础之约束
MySQL基础之约束 概述 概念:约束是作用在字段的规则,限制表中数据 演示 # 多个约束之间不需要加逗号 # auto_increment 自增 create table user(id int primary key auto_increment comment 主键,name varchar(10) not null unique comment 姓名,age i…...

2024新版IDEA创建JSP项目
1. 创建项目 依次点击file->new->Project 配置如下信息并点击create创建项目 2. 配置Web项目 点击file->Project Structure 在点击Project Settings->Module右键右边模块名称->ADD->Web 点击Create Artifact 出现如下界面就表示配置完毕,…...