当前位置: 首页 > news >正文

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动态代理的使用&#xff0c;不对源码进行深入分析。代码可直接复制使用。 类型 机制 回调方式 适用场景 效率 JDK动态代理 委托机制。代理类和目标类都实现了同样的接口。InvocationHandler持有目标类。代理类委托InvocationHandler去调用目标类原…...

[C++]使用纯opencv部署yolov11-pose姿态估计onnx模型

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

python you-get下载视频

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

SCUC博客摘录「 储能参与电能市场联合出清:SCUC和SCED模型应用于辅助服务调频市场(IEEE39节点系统)」2024年10月6日

2.1 SCUC模型在本方法中&#xff0c;首先利用SCUC模型确定机组出力计划和储能充放电计划。SCUC模型是电力系统经济调度的重要工具&#xff0c;通过优化发电机组出力计划和调度&#xff0c;实现电力系统的经济性和可靠性。在考虑储能的情况下&#xff0c;SCUC模型需要考虑储能的…...

Git分支-团队协作以及GitHub操作

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

力扣刷题 | 两数之和

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

[C#]winform部署官方yolov11-obb旋转框检测的onnx模型

【官方框架地址】 https://github.com/ultralytics/ultralytics 【算法介绍】 Yolov11-obb&#xff08;You Only Look Once version 8 with Oriented Bounding Boxes&#xff09;是一种先进的对象检测算法&#xff0c;它在传统的Yolov3和Yolov4基础上进行了优化&#xff0c;加…...

【GC日志和OOM日志分析】JVM GC日志和OOM Dump文件分析

1 缘起 充电、充电、充电。 增加一些必备的知识&#xff0c;帮助后续使用。 2 配置JVM参数 为分析GC日志以及OOM相关信息&#xff0c;配置JVM参数&#xff0c;分为三个部分&#xff1a; &#xff08;1&#xff09;堆内存&#xff0c;包括年轻代、最大堆内存&#xff1b; &a…...

【电路】1.1 实际电路和电路模型

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

Vue - 打包部署

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

spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理)

文章目录 【README】【1】文件上传与MultipartResolver【1.1】使用MultipartResolver进行文件上传【1.2】springmvc处理multipart多部件请求流程【1.3】使用springmvc上传文件代码实现&#xff08;springmvc6.10版本&#xff09;&#xff1a; 【2】Handler与HandlerAdaptor&…...

springboot项目中属性的使用优先级;maven编译插件切换环境变量

概述 在项目部署时&#xff0c;相关的生产环境和测试环境是分开的&#xff0c;但是代码是同一套&#xff1b; 所以一般会有多套变量&#xff1b; 项目中默认变量&#xff08;一般是测试环境&#xff09; 线上变量&#xff08;线上数据较敏感&#xff0c;一般也不会放在代码中&…...

【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关---浦语提示词工程实践

学员闯关手册&#xff1a;https://aicarrier.feishu.cn/wiki/ZcgkwqteZi9s4ZkYr0Gcayg1n1g?open_in_browsertrue 课程视频&#xff1a;https://www.bilibili.com/video/BV1cU411S7iV/ 课程文档&#xff1a; https://github.com/InternLM/Tutorial/tree/camp3/docs/L1/Prompt 关…...

OpenCV视频I/O(11)视频采集类VideoCapture之设置视频捕获设备的属性函数 set()的使用

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

数据结构之树(3)

一、森林和树的转换 重要&#xff01; 树->二叉树 由于孩子兄弟链式存储和二叉树链式存储本质相同&#xff0c;故树可转换为二叉树。 森林->二叉树 森林&#xff1a;m棵互不相交的树的集合 森林->树 树->二叉树 森林中各个树的根节点之间视为兄弟关系 二、树…...

螺蛳壳里做道场:老破机搭建的私人数据中心---Centos下docker学习02(yum源切换及docker安装配置)

2 前期工作 2.1 切换yum源并更新 删除/etc/yum.repos.d/原有repo文件&#xff0c;将Centos-7.repo库文件拷贝到该目录下。 然后清楚原有缓存yum clean all 生成新的缓存yum makecache 更新yum update –y 然后再确认/etc/yum.repos.d/不会有其他库文件&#xff0c;只留下…...

强化学习笔记之【Q-learning算法和DQN算法】

强化学习笔记&#xff08;一&#xff09;——Q-learning和DQN算法核心公式 文章目录 强化学习笔记&#xff08;一&#xff09;——Q-learning和DQN算法核心公式前言&#xff1a;Q-learning算法DQN算法 前言&#xff1a; 强化学习领域&#xff0c;繁冗复杂的大段代码里面&#…...

面试经验02

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

分层图 的尝试学习 1.0

分层图&#xff1a; 分层图的最短路&#xff1a; 又叫做 扩点最短路。不把实际位置看做是图上的点&#xff0c;而是把实际位置及其状态的组合&#xff0c;&#xff08;一个点有若干的状态&#xff0c;所以一个点会扩充出来若干点&#xff09;看做是图上的点&#xff0c;然后搜索…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

JavaScript 标签加载

目录 JavaScript 标签加载script 标签的 async 和 defer 属性&#xff0c;分别代表什么&#xff0c;有什么区别1. 普通 script 标签2. async 属性3. defer 属性4. type"module"5. 各种加载方式的对比6. 使用建议 JavaScript 标签加载 script 标签的 async 和 defer …...

IP选择注意事项

IP选择注意事项 MTP、FTP、EFUSE、EMEMORY选择时&#xff0c;需要考虑以下参数&#xff0c;然后确定后选择IP。 容量工作电压范围温度范围擦除、烧写速度/耗时读取所有bit的时间待机功耗擦写、烧写功耗面积所需要的mask layer...

运动控制--BLDC电机

一、电机的分类 按照供电电源 1.直流电机 1.1 有刷直流电机(BDC) 通过电刷与换向器实现电流方向切换&#xff0c;典型应用于电动工具、玩具等 1.2 无刷直流电机&#xff08;BLDC&#xff09; 电子换向替代机械电刷&#xff0c;具有高可靠性&#xff0c;常用于无人机、高端家电…...