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

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径&#xff0c;但是vite中默认不可以。 如何实现&#xff1a; vite中提供了resolve.alias&#xff1a;通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

Python实现简单音频数据压缩与解压算法

Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中&#xff0c;压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言&#xff0c;提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里

写一个shell脚本&#xff0c;把局域网内&#xff0c;把能ping通的IP和不能ping通的IP分类&#xff0c;并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...