当前位置: 首页 > 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;然后搜索…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...