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

2024-06-22 06:30

本文主要是介绍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 介绍和实战 。

java agent技术原理及简单实现 。

这篇关于idea插件开发之一起来开发个打印方法入参和返回值的插件吧!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1083536

相关文章

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

RabbitMQ 延时队列插件安装与使用示例详解(基于 Delayed Message Plugin)

《RabbitMQ延时队列插件安装与使用示例详解(基于DelayedMessagePlugin)》本文详解RabbitMQ通过安装rabbitmq_delayed_message_exchan... 目录 一、什么是 RabbitMQ 延时队列? 二、安装前准备✅ RabbitMQ 环境要求 三、安装延时队

504 Gateway Timeout网关超时的根源及完美解决方法

《504GatewayTimeout网关超时的根源及完美解决方法》在日常开发和运维过程中,504GatewayTimeout错误是常见的网络问题之一,尤其是在使用反向代理(如Nginx)或... 目录引言为什么会出现 504 错误?1. 探索 504 Gateway Timeout 错误的根源 1.1 后端

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模