字节码编程bytebuddy之获取方法信息和方法入参信息

写在前面

本文看下通过bytebuddy如何获取方法信息和方法的入参信息。

1:代码

package com.dahuyou.bytebuddy.bb;import com.dahuyou.bytebuddy.TT;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.*;
import net.bytebuddy.matcher.ElementMatchers;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.Callable;public class TTT {public static void main(String[] args) throws Exception {DynamicType.Unloaded<BizMethod> dynamicType = new ByteBuddy().subclass(BizMethod.class).method(ElementMatchers.named("queryUserInfo")).intercept(MethodDelegation.to(PrintMethodInfo.class)).make();DynamicType.Loaded<com.dahuyou.bytebuddy.bb.BizMethod> load = dynamicType.load(com.dahuyou.bytebuddy.aa.TTT.class.getClassLoader());// 执行插桩后的代码Class<? extends com.dahuyou.bytebuddy.bb.BizMethod> calzzz = load.getLoaded();calzzz.getMethod("queryUserInfo", String.class, String.class).invoke(calzzz.newInstance(), "89899", "黑咯Heloise");outputClazz(load.getBytes());}private static void outputClazz(byte[] bytes) {// 输出类字节码FileOutputStream out = null;try {String pathName = TT.class.getResource("/").getPath() + "AsmTestPrintMethodParam.class";out = new FileOutputStream(new File(pathName));System.out.println("ASM类输出路径:" + pathName);out.write(bytes);} catch (Exception e) {e.printStackTrace();} finally {if (null != out) try {out.close();} catch (IOException e) {e.printStackTrace();}}}public static class PrintMethodInfo {// 通过该注解标记为要执行的方法@RuntimeTypepublic static Object realRun(@SuperCall Callable<?> callable,@Origin Method method,@AllArguments Object[] args,@Argument(0) Object firstParam) throws Exception {long start = System.currentTimeMillis();Object resObj = null;try {resObj = callable.call();return resObj;} finally {System.out.println("方法名称:" + method.getName());System.out.println("入参值:" + Arrays.asList(args));System.out.println("第一个入参值:" + firstParam);System.out.println("入参个数:" + method.getParameterCount());System.out.println("入参类型:" + method.getParameterTypes()[0].getTypeName() + "、" + method.getParameterTypes()[1].getTypeName());System.out.println("出参类型:" + method.getReturnType().getName());System.out.println("出参结果:" + resObj);System.out.println("方法耗时:" + (System.currentTimeMillis() - start) + "ms");}}}
}

其中通过注解@Origin获取原始的方法对象,通过注解@AllArguments获取所有的入参,也可以通过@Argument(索引位置)来获取指定位置的参数,运行如下:

BizMethod.queryUserInfo
方法名称:queryUserInfo
入参值:[89899, 黑咯Heloise]
第一个入参值:89899
入参个数:2
入参类型:java.lang.String、java.lang.String
出参类型:java.lang.String
出参结果:bytebuddy 搞一搞吧!!!
方法耗时:25msProcess finished with exit code 0

生成的字节码如下:

package com.dahuyou.bytebuddy.bb;import com.dahuyou.bytebuddy.bb.BizMethod.ByteBuddy.XE2b1UHs.auxiliary.45oW83hf;
import com.dahuyou.bytebuddy.bb.TTT.PrintMethodInfo;public class BizMethod$ByteBuddy$XE2b1UHs extends BizMethod {public String queryUserInfo(String var1, String var2) throws InterruptedException {return (String)PrintMethodInfo.realRun(new 45oW83hf(this, var1, var2), cachedValue$ZzEPIYTs$gvqiiu0, new Object[]{var1, var2}, var1);}public BizMethod$ByteBuddy$XE2b1UHs() {}
}

可以看到bytebuddy是通过生成待增强类的子类来完成插桩的,也可以说是使用了代理、包装的思想,然后通过注解预留了很多的口让我们获取一些可能需要用到的信息。精妙的设计,完美屏蔽了复杂度,还保留了扩展性。

写在后面

参考文章列表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/43164.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【高中数学/对数函数】比较a=ln2/2,b=ln5/5的大小

【问题】 比较aln2/2,bln5/5的大小 【解答】 a-bln2/2-ln5/5(5*ln2-2*ln5)/10(ln2^5-ln5^2)/10(ln32-ln25)/10>0 所以a>b 【图像】 如果绘出函数ylnx/x的图像&#xff0c;再标记出a,b的位置&#xff0c;则绘出图像如下&#xff1a; 由上图可以看出&#xff0c;a,b两…

随手记:对比两个对象不一样的值,生成一个新的对象

diffObject(obj1, obj2) {let changeForm {}for (let key in obj1) {if (!obj1.hasOwnProperty(key) || obj1[key] ! obj2[key]) {// 新旧数据不相同的key值changeForm[key] obj1[key]}}console.log(changeForm, changeForm)},

初次用bable遍历vue项目下的中文

利用 babel 找到 AST 中的中文 // vite-plugin-babel-transform.js const parser require(babel/parser) const traverse require(babel/traverse).default // const types require(babel/types) // const generate require(babel/generator).default const fs require(f…

【PHP小课堂】学习PHP中的字符串操作函数(二)

学习PHP中的字符串操作函数&#xff08;二&#xff09; 接下来我们继续 PHP 中字符串函数的学习。今天学习的内容主要是带下划线的一些字符串函数&#xff0c;上篇文章说过&#xff0c;这些系统函数的命名是 PHP 非常令人诟病的&#xff0c;有些东西真的只能靠我们的记忆来强行…

显卡、显卡驱动、cuda、cuDNN之间关系

显卡、显卡驱动、CUDA 和 cuDNN 是构成高性能计算和深度学习环境的关键组件&#xff0c;它们之间有着紧密的联系。下面是对这些组件及其关系的详细介绍&#xff1a; 显卡&#xff08;GPU&#xff09; 显卡&#xff0c;全称为图形处理器&#xff08;Graphics Processing Unit&…

【Unity2D 2022:NPC】制作任务系统

一、接受任务 1. 编辑NPC对话脚本&#xff1a; &#xff08;1&#xff09;创建静态布尔变量用来判断ruby是否接受到任务 public class NPCDialog : MonoBehaviour {// 创建全局变量用来判断ruby是否接到任务public static bool receiveTask false; } &#xff08;2&#xff…

python学习-错误与异常

代码是人的逻辑思维的具体体现&#xff0c;因为没有一个人的逻辑思维是完美无缺的&#xff0c;所以人在编写代码时必然会出现各种错误。既然错误或多或少都会发生&#xff0c;那么如何捕捉错误&#xff0c;并且捕捉到错误后要如何处理&#xff0c;就显得很重要。 语法错误 Py…

SPI通信协议和W25Q64

前言&#xff1a; STM32中的通信接口&#xff1a; UART 单总线 IIC SPI CAN 1. SPI FLASH W25Q64的关系 SPI:一种通信接口&#xff0c;可以用于和搭载SPI接口的设备通信 FLASH:是一种掉电不丢失的存储 -- 手机8256G的256 单片机 64K512K的512 芯片内部flash&…

STM32 GPIO的工作原理

STM32的GPIO管脚有下面8种可能的配置:&#xff08;4输入 2 输出 2 复用输出) &#xff08;1&#xff09;浮空输入_IN_FLOATING 在上图上&#xff0c;阴影的部分处于不工作状态&#xff0c;尤其是下半部分的输出电路&#xff0c;实际上是与端口处于隔离状态。黄色的高亮部分显示…

响应式布局下关于gird栅格布局的一些构思

1、传列数&#xff0c;根据列数计算元素容器宽度 好处是子元素可以写百分比宽度&#xff0c;不用固定某一种宽度&#xff0c;反正知道列数通过计算间距就能得到外层容器的宽度。 举个简单的例子&#xff1a; &#xff08;ps:以下用例皆在html中去模拟&#xff0c;就不另外起r…

Python 获取 SQL 指纹和 HASH 值

前言 本文介绍一个提取 SQL 指纹的方法&#xff0c;就是将 SQL 语句的条件转换为 &#xff1f;可用于脱敏和 SQL 聚类分析的场景。 1. 工具安装 这里用到的工具&#xff0c;就是 pt 工具集中的 pt-fingerprint 含在 Percona Toolkit 中&#xff0c;安装方法可参考 Percona T…

python7:装饰器

目录 1.调用外部程序os.system-阻塞式调用subprocess-python中的模块 2.装饰器前戏作用域&#xff08;1&#xff09;全局和局部-就近原则&#xff08;2&#xff09;嵌套作用域&#xff08;3&#xff09;内置作用域、变量 高阶函数&#xff1a;函数是最高级的对象&#xff08;1&…

海外媒体投稿:5个软文代发经典案例,教大家获得突破

随着互联网的飞速发展&#xff0c;软文代发成为一种高效的推广方法。下面我们就详细介绍五个成功软文代发推广实例&#xff0c;致力于帮助读者把握有关方法&#xff0c;完成突破。 第一实例&#xff1a;社交网络散播在如今社交媒体时代&#xff0c;软文代发能够通过社交平台迅速…

nodejs实现:支付宝订单查询

nodejs实现&#xff1a;支付宝订单查询&#xff1b; 原生http请求&#xff0c;不使用三方库&#xff1b; 代码如下&#xff1a; const https require(https); const crypto require(crypto); const querystring require(querystring);// 支付宝公共参数 const PRIVATE_KE…

[C++] 轻熟类和对象

类的定义 格式规范 class为定义类的关键字&#xff0c;后有类名&#xff0c;类的主体存于{}中&#xff1b;类定义结束时后面的分号不能省略&#xff1b;类体的内容成为类的成员&#xff0c;类中的变量成为成员变量&#xff0c;函数成为方法或成员函数&#xff1b;C兼容C语言的…

微软 Edge 浏览器全解析

微软 Edge 是微软推出的一个现代化浏览器,继承了 Internet Explorer(IE)的部分功能,但在速度、安全性和兼容性方面做出了很大改进。下面是对微软 Edge 浏览器的详细解析,包括其特点、安装、配置和常见问题的解答。 微软 Edge 浏览器的特点 基于 Chromium 内核 Edge 浏览…

SpringBoot配置flyway

背景 目前我们的项目代码都会交由Git、SVN等版本管理工具进行管理&#xff0c;但是我们的sql脚本&#xff0c;尤其是各类ddl脚本并没有进行版本的管理&#xff08;python的web框架Django默认就提供了类似的工具&#xff0c;从一开始就鼓励开发者通过版本管理的方式进行数据库的…

C++中的多重继承和虚继承:横向继承、纵向继承和联合继承;虚继承

多重继承 A.横向多重继承&#xff1a; B.纵向多重继承&#xff1a; C.联合多重继承&#xff1a; 因为 single 和 waiter 都继承了一个 worker 组件&#xff0c;因此 SingingWaiter 将包含两个 worker 组件&#xff0c;那么将派生类对象的地址赋给基类指针将出现二义性 那么如何…

idea http client插件上传文件,并忽略https证书验证

上传文件 ### 传临时素材 图片 POST https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token{{access_token}}&typeimage Content-Type: multipart/form-data; boundary----WebKitFormBoundarywKUX3Xj6aL5Wssnb------WebKitFormBoundarywKUX3Xj6aL5Wssnb Conten…

从Helm到 Operator:Kubernetes应用管理的进化

&#x1f9f0;Helm 的作用 在开始前需要先对 kubernetes Operator 有个简单的认识。 以为我们在编写部署一些简单 Deployment 的时候只需要自己编写一个 yaml 文件然后 kubectl apply 即可。 apiVersion: apps/v1 kind: Deployment metadata: labels: app: k8s-combat …