idea插件开发之一起来开发个打印方法入参和返回值的插件吧!

写在前面

源码 。
在开发过程中为了调试代码我们就可能就需要知道某个方法入参的值是什么,或者是返回值是什么。此时,我们的解决办法一般都是debug,但是debug的效率说实话其实是不高的,特别是不断的调试,不断的debug。所以为了解决(😅,彻底解决不用debug,不太可能,但肯定能在一定程度上缓解吧)这个痛点问题,我们就来尝试开发一个idea插件吧。

1:编写agent程序

通过bytebuddy来实现字节码插桩,源码如下:

public class MyPreAgent {// 如果有该方法则优先调用这个有两个参数的方法public static void premain(String agentArgs, Instrumentation inst) {AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {return builder
//                    .method(ElementMatchers.named("executeInternal")) // 拦截任意方法.method(ElementMatchers.named("m1").or(ElementMatchers.named("m2"))) // 拦截任意方法.intercept(MethodDelegation.to(MonitorMethod.class)); // 委托};new AgentBuilder.Default()
//                .type(ElementMatchers.nameStartsWith("com.mysql.cj.jdbc.ClientPreparedStatement")).type(ElementMatchers.nameStartsWith("com.dahuyou.agent.test.MyCls")).transform(transformer).installOn(inst);}// 如果是没有上面的方法则调用这个一个参数的方法public static void premain(String agentArgs) {}}

在代码中我们设置了满足什么规则才拦截,这里是固定写死的拦截类com.dahuyou.agent.test.MyCls的方法m1和m2,当然可以随意改,或者是通过某种配置的方式做成活的,上述的类MonitorMethod即为插装的代码,源码如下:

public class MonitorMethod {@RuntimeTypepublic static Object intercept(@This Object obj, @Origin Method method, @SuperCall Callable<?> callable, @AllArguments Object... args) throws Exception {System.out.println("MonitorMethod.intercept...");long start = System.currentTimeMillis();Object resultObj = null;try {resultObj = callable.call();return resultObj;} finally {System.out.println("方法名称:" + method.getName() + "入参个数:" + method.getParameterCount());for (int i = 0; i < method.getParameterCount(); i++) {System.out.println("入参 Idx:" + (i + 1) + " 类型:" + method.getParameterTypes()[i].getName() + " 内容:" + args[i]);}System.out.println("出参类型:" + method.getReturnType().getName());System.out.println("出参结果:" + resultObj);System.out.println("方法耗时:" + (System.currentTimeMillis() - start) + "ms");}}}

接着我们就可以生成agent的jar包来测试了,如下:
在这里插入图片描述
然后创建一个满足agent匹配规则的类:

public class MyCls {public String m1(String name) {System.out.println("m1方法执行了啊: " + name);this.m2(30, "一个啊神秘的地方");return name;}private int m2(int age, String addr) {System.out.println("m2方法执行了啊: " + age);return ++age;}
}

测试类:

public class MyPreAgentTest {public static void main(String[] args) {String name = "张三";new MyCls().m1(name);}
}

然后配置VM option添加-javaagent,如下:
在这里插入图片描述
最后运行测试:
在这里插入图片描述

接着就可以来继续开发插件了。

2:编写idea插件

要想让agent工作,必须通过-javaagent添加到java运行命令中,idea提供了java.programPatcher的扩展可以让我们实现这个需求,具体是继承抽象类JavaProgramPatcher,然后修改其中的入参RunProfile:

/*** 向Java cmd中动态添加-javaagent:xxx*/
public class JavaCmdEditor extends JavaProgramPatcher {@Overridepublic void patchJavaParameters(Executor executor, RunProfile configuration, JavaParameters javaParameters) {String agentCoreJarPath = PluginUtil.getAgentCoreJarPath();RunConfiguration runConfiguration = (RunConfiguration) configuration;ParametersList vmParametersList = javaParameters.getVMParametersList();// 向运行参数中增加-javaagent:/path/to/the-show-sql-agent.jarvmParametersList.addParametersString("-javaagent:" + agentCoreJarPath);vmParametersList.addNotEmptyProperty("com.dahuyou.the-probe-plugin", runConfiguration.getProject().getLocationHash());}
}

这样还不行,为了让idea加载运行,还需要配置到plugin.xml中的java.ProgramPatcher中:

<extensions defaultExtensionNs="com.intellij"><!-- Add your extensions here --><java.programPatcher implementation="com.dahuyou.probe.plugin.JavaCmdEditor"/>
</extensions>

然后就可以来测试了:
在这里插入图片描述
运行:
在这里插入图片描述
到这里还有一个问题需要解决,即插装的类和方法是固定写死的,接下来我们开发一个UI来允许配置想要拦截的类和方法,就基本全了。

3:插桩代码支持配置

首先开发一个action,在file中增加一个按钮入口:

public class AgentSettingAction extends AnAction {@Overridepublic void actionPerformed(AnActionEvent e) {Messages.showInfoMessage("即将跳转到agent设置页面", "提示");// 弹出一个设置(implements Configurable)页面(extends JPanel)ShowSettingsUtil.getInstance().editConfigurable(e.getProject(), new AgentSettingUI());}
}

这里AgentSettingUI是需要我们自定义的页面,继承了Japnel,并实现了Configurable接口:

public class AgentSettingUI extends JPanel implements Configurable {}

效果如下:
在这里插入图片描述
点击ok会调用apply方法,在该方法中会将用户设置的信息写到本地文件中:
在这里插入图片描述
接着还需要改造agent程序,动态的从文件中读取数据来进行拦截配置:

public static void premain(String agentArgs, Instrumentation inst) {String agentSettingFilePath = "D:/agentsetting.txt";String packagePrefix = "";List<String> methodList = null;try {BufferedReader br = new BufferedReader(new FileReader(agentSettingFilePath));String agentSettingInfo = br.readLine();// com.dahuyou3343#tttmyFn1,myFn2System.out.println("agentSettingInfo: " + agentSettingInfo);String[] split = agentSettingInfo.split("#");packagePrefix = split[0];methodList = Arrays.asList(split[1].split(","));System.out.println("packagePrefix: " + packagePrefix);System.out.println("methodList111: " + methodList);} catch (Exception e) {e.printStackTrace();}List<String> finalMethodList = methodList;AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {ElementMatcher.Junction<NamedElement> named = ElementMatchers.named(finalMethodList.get(0));for (int i = 1; i < finalMethodList.size(); i++) {named = named.or(ElementMatchers.named(finalMethodList.get(i)));}return builder.method(named) // 拦截任意方法.intercept(MethodDelegation.to(MonitorMethod.class)); // 委托};new AgentBuilder.Default().type(ElementMatchers.nameStartsWith(packagePrefix)).transform(transformer).installOn(inst);
}

注意打一个新的agent jar包放在插件模块的libs目录中,接着我们来测试,只拦截m1,不拦截m2:
在这里插入图片描述
在这里插入图片描述
设置一个错误的包前缀,都不拦截:
在这里插入图片描述
在这里插入图片描述

4:在idea中安装

首先打包:
在这里插入图片描述
安装到idea也比较简单,你可以直接下载 然后安装到你的idea中,安装也很简单,可以直接拖拽到idea中松手,会提示你重启,也可以通过file->settings->plugins:
在这里插入图片描述
然后选择zip包安装,也会提示你重启idea,重启后就可以使用该插件了,对了插件的名字叫:debug小助手
在这里插入图片描述

5:实际使用

假设有如下的springboot项目:

@SpringBootApplication
@RestController
public class AAApplication {public static void main(String[] args) {SpringApplication.run(AAApplication.class);}@RequestMapping("/sayHi")@ResponseBodypublic String sayHi(String name) {new MyCls().m1(name);return name + ",hi!";}
}

测试同学说你的sayHi接口,错误,此时如果你怀疑是入参问题,就可以用这个插件了(是不是就不用debug了🤭🤭🤭,提高效率杠杆的),如下:
在这里插入图片描述

你安装使用了吗?是的话就点个赞让我知道下吧🙁🙁🙁!!!如果你有对这个插件有什么建议,或者其他的想法,就留言告诉我吧,我们一起进步,让自己在这互联网寒潮中不做那批被淘汰的人💪💪💪!!!

写在后面

参考文章列表

Java Agent 介绍和实战 。

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

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

相关文章

KT148A-SOP8语音芯片接收到一线串口指令到播放声音大概多长时间

一、问题简介 请问KT148A-SOP8语音芯片接收到一线串口指令&#xff0c;到播放出来声音&#xff0c;大概需要多长时间 我的需求是做按键提示音&#xff0c;初测了一下感觉有延时&#xff0c;这个要如何处理 详细说明 KT148A从接收到指令&#xff0c;到执行&#xff0c;到播放…

JavaScript基于时间的动画算法

前段时间无聊或有聊地做了几个移动端的HTML5游戏。放在不同的移动端平台上进行测试后有了诡异的发现&#xff0c;有些手机的动画会“快”一点&#xff0c;有些手机的动画会“慢”一点&#xff0c;有些慢得还不是一两点。 通过查找资料发现&#xff0c;基于帧的算法&#xff08…

多模态大模型时代下的文档图像智能分析与处理

0. 前言 随着人工智能技术的不断发展&#xff0c;尤其是深度学习技术的广泛应用&#xff0c;多模态数据处理和大模型训练已成为当下研究的热点之一&#xff0c;这些技术也为文档图像智能处理和分析领域带来了新的发展机遇。 多模态大模型时代下的文档图像智能分析与处理的研究…

Linux:用户账号和权限管理的命令

目录 一、Linux用户的分类和组的分类 1.1、用户账号和组账号 1.2、用户的分类 1.3、组账号 1.4、用户账号文件/etc/passwd 二、用户管理相关命令 2.1、chage命令&#xff1a;用来修改帐号和密码的有效期限&#xff0c;针对目前系统已经存在的用户 2.2、useradd&#xf…

【Numpy】一文向您详细介绍 np.abs()

【Numpy】一文向您详细介绍 np.abs() 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通本硕&#xff0c;曾…

数据结构-图的基本概念

图的定义 图时由非空的顶点集合和一个描述顶点之间关系的集合组成。可以定义为&#xff1a; ​​​​​​​ ​​​​​​​ ​​​​​​​ G表示一个图&#xff0c;V表示点集&#xff0c;E表示边集。集合E的每一个二元组都包含两个值和&#xff0c;表示…

什么是联盟营销?独立站如何通过联盟营销提高转化率?

什么是联盟营销&#xff1f;独立站如何通过联盟营销提高转化率&#xff1f; 流量紧缺是跨境电商独立站永恒不变的难题&#xff0c;对于独立站卖家来说&#xff0c;广告投放、KOL引流等推广方式都能带来流量&#xff0c;但在广告流量越来越贵的今天&#xff0c;对于跨境电商独立…

Vue快速上手和Vue指令

一、Vue快速上手 1、Vue概念 Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套构建用户界面的渐进式框架 Vue2官网&#xff1a;https://v2.cn.vuejs.org/ 构建用户界面&#xff1a;基于数据渲染出用户可以看到的界面 渐进式&#xff1a; 循序渐进&#xff0c;不一定非得把…

阿里云PAI主机网页访问测试

笔者使用的阿里云平台PAI主机(首次使用免费三个月额度)&#xff0c;由于其默认不设置公网IP&#xff0c;所以在该主机上启动HTTP服务后无法访问测试。 这里使用ssh来作隧道穿透&#xff0c;首先需要配置ssh。 云主机配置ssh 1. 修改root账号密码 在云主机上执行 passwd ro…

安当透明加密(TDE)助力企业建立可信赖的数据环境

​​​​​​​ 透明加密是一种特殊的加密方法&#xff0c;它允许数据在存储或传输过程中自动进行加密和解密&#xff0c;而用户并不需要知道加密过程。这种技术对用户来说是“透明的”&#xff0c;因为它不会改变用户的日常操作习惯&#xff0c;加密和解密过程在后台自动进行…

怎么学习PMP才是最正确的?

每个人的学习方式各不相同&#xff0c;不能一概而论说某种学习方式就是错误的。学习方式并没有绝对的对错之分&#xff0c;只能说是否适合自己&#xff0c;是否能够达到预期的学习效果。并不是别人的学习方式就一定适合自己&#xff0c;也不是不适合自己的学习方式就一定是错误…

【ARMv8/v9 GIC 系列 4 -- GIC 中断分类 SGI | PPI | SPI 及中断检测流程】

文章目录 GIC 中断分类SGI&#xff08;Software Generated Interrupts&#xff09;PPI&#xff08;Per-Processor Interrupts&#xff09;SPI&#xff08;Shared Peripheral Interrupts&#xff09; 中断检测流程物理中断生命周期SPI 中断检测流程PPI 和SGI中断检测流程LPI中断…

Centos SFTP搭建

SFTP配置、连接及挂载教程_sftp连接-CSDN博客1、确认是否安装yum list installed | grep openssh-server 2、创建用户和组 sudo groupadd tksftpgroup sudo useradd -g tksftpgroup -d /home/www/tk_data -s /sbin/nologin tksftp01 sudo passwd tksftp013. 配置SFTP注意&a…

Unet已死,Transformer当立!详细解读基于DiT的开源视频生成大模型EasyAnimate

Diffusion Models视频生成-博客汇总 前言&#xff1a;最近阿里云PIA团队开源了基于Diffusion Transformer结构的视频生成模型EasyAnimate&#xff0c;并且提出了专门针对视频的slice VAE&#xff0c;对于目前基于Unet结构的视频生成最好如SVD形成了降维打击&#xff0c;不论是生…

Apifox 快速入门教程

访问示例项目​ 可访问Apifox官网&#xff0c;下载并打开 Apifox 后&#xff0c;你将会看到由系统自动创建的“示例团队”&#xff0c;其中内含一个“示例项目”。 项目中自动生成了与宠物商店有关的数条接口。 手动新建接口​ 新建接口是开发者们最常用的功能之一。Apifox 能…

提升运营设计水平的8个关键技巧

运营设计是建立更强大的设计团队&#xff0c;支持个人、流程和工具的协调&#xff0c;大规模扩大创造力和影响力的一种以人为本的方法。设计和操作通过敏捷和迭代的方法完全改变了开发过程&#xff0c;允许组织跨团队快速扩展和迭代设计过程。一个庞大的运营设计团队应该如何协…

嵌入式虚拟仿真创新教学方案,解决芯片原理讲解抽象、依赖大量硬件平台、系统化教学难三大难题

嵌入式技术起源早&#xff0c;市场需求旺盛&#xff0c;被广泛应用于各个领域&#xff0c;从智能家居到智慧城市&#xff0c;从工业自动化到医疗健康&#xff0c;嵌入式系统深度落地于各类智能设备与系统之中&#xff0c;支撑起物联网的发展。随着物联网与人工智能的迅速发展&a…

NGINX_十八 nginx 访问控制

十八 nginx 访问控制 1 nginx 访问控制模块 &#xff08;1&#xff09;基于IP的访问控制&#xff1a;http_access_module &#xff08;2&#xff09;基于用户的信任登录&#xff1a;http_auth_basic_module 2 基于IP的访问控制 2.1 配置语法 Syntax&#xff1a;allow addr…

《Windows API每日一练》5.2 按键消息

上一节中我们得知&#xff0c;Windows系统的按键消息有很多类型&#xff0c;大部分按键消息都是由Windows系统的默认窗口过程处理的&#xff0c;我们自己只需要处理少数几个按键消息。这一节我们将详细讲述Windows系统的所有按键消息及其处理方式。 本节必须掌握的知识点&…

解决IDEA使用卡顿的问题,设置JVM内存大小和清理缓存

解决IntelliJ IDEA中卡顿问题&#xff0c;可以尝试以下几个常见且有效的步骤&#xff1a; 1 增加IDEA的JVM内存分配&#xff1a; 位于IDEA安装目录的bin文件夹下&#xff0c;找到对应的操作系统配置文件&#xff08;idea64.exe.vmoptions&#xff08;Windows&#xff09;或id…