文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

基于IDEA插件开发和字节码插桩技术,实现研发交付质量自动分析

2024-12-03 11:44

关注

本文转载自微信公众号「bugstack虫洞栈」,作者小傅哥 。转载本文请联系bugstack虫洞栈公众号。

目录

一、前言

二、技术实现准备

三、对字节码插桩

四、IDEA 插件开发

五、效果演示

六、总结

七、系列推荐

一、前言

如何保证代码质量?

业务提需求,产品定方案,研发做实现,测试验流程。四种角色的相互配合是确保一个需求上线的必备条件。在整个需求的交付质量级别划分中,研发与测试是非常重的一环,如果研发提测的代码质量不高,就会出现不同级别的修BUG、返工甚至重做的风险。

那么,怎么来提高代码质量呢?一般我们都会要求研发在开发代码的过程中编写单元测试,验证自己的代码逻辑。如果最终单元测试覆盖度不足,可以由测试拒绝研发提测。

但是,整个需求实现的代码是在全部开发完成后提测的,也就是临近上线的最后一环,大家才知道某个研发的某个功能域的实现是否具备提测条件。如果这个时候代码质量不高,那么接下来就是项目风险的时候。压测试时间、调上线时间,总之有病拖着最后成大病了!

当然,你可以在项目开发期间定期排查代码,或者在日会进度反馈等等手段。可这样需要耗费大量时间1拖1的开发排查方式很难满足复杂流程的较大型项目开发,而且对于项目风险把控也是不可预估的。

所以,我们希望采集研发在开发过程中的执行动作,把风险判断提前。实际操作举例就是,当你开发完成一个接口,开始测试运行时,我们的插件就可以采集到这个接口的全部信息,包括:接口名称、入参类型和内容、出参类型和内容、异常信息、调用关系链等。而再把这些信息汇总提交到服务端,生成本次需求代码分支下的全部接口动作,以及各系统间的关系链路,并附带随时生成最新的接口文档和一键测试验证功能。后期测试人员介入时就可以参考研发在编码过程中的全部测试用例,也可以查看整个功能的覆盖程度,此外测试人员测试过程中的数据也会被保留下。现在拥有这些数据信息以后,就可以完整的生成一套研发测试质量交付全览图,让整个工程开发交付质量评估透明化。

接下来我们就按照以上的描述性内容,实践开发一个案例体会下。走起!

二、技术实现准备

  1. 字节码插桩,因为我们需要采集到接口执行信息,那么就需要使用字节码插桩组件给接口方法增强。这个实现有点类似谷歌的Dapper,大规模分布式架构的非入侵监控。只不过我们需要采集的描述性信息更多。关于字节码插桩,可以了解ASM、Javassist、Byte-Buddy,它们都可以做此项工作。
  2. IDEA 插件开发,因为我们需要在研发人员开发过程中进行采集,也不破坏研发的操作习惯。那么最好的方式就是嵌入到启动运行中,只要在开发过程中有运行代码的动作,就采集相应的接口信息。
  3. 最后就是数据的传输和处理,传输可以使用MQ或者直接用Netty。而处理数据的过程会相对比较复杂,在这个过程需要分析出有价值的数据,同类的数据,合并一条执行链路的数据,以及生成相关的接口文档和工程服务地图。

三、对字节码插桩

这里我们使用的字节码插桩组件是 Byte-buddy,它是一个代码生成和操作库,用于在Java 应用程序运行时创建和修改 Java 类,而无需编译器的帮助。除了 Java 类库附带的代码生成实用程序外,Byte Buddy 还允许创建任意类,并且不限于实现用于创建运行时代理的接口。此外,Byte Buddy 提供了一种方便的 API,可以使用 Java 代理或在构建过程中手动更改类。

1. 方法入口

  1. public static void premain(String agentArgs, Instrumentation inst) { 
  2.     AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> { 
  3.         return builder 
  4.                 .method(ElementMatchers.any()) // 拦截任意方法 
  5.                 .intercept(MethodDelegation.to(MonitorMethod.class)); 
  6.     }; 
  7.     new AgentBuilder 
  8.             .Default() 
  9.             .type(ElementMatchers.nameStartsWith(agentArgs))  
  10.             .transform(transformer) 
  11.             .installOn(inst); 

如果你接触过 Javaagent 开发,那么对于 premain 会比较熟悉。如果不清楚你可以把它理解为,它是程序启动的时的方法入口,你可以从这个入口中拦截到你需要的方法,之后对它进行字节码增强。其实也就是动态写代码,在方法中添加你的代码,来收集方法信息。

2. 采集信息

  1. @RuntimeType 
  2. public static Object intercept(@Origin Method method, @SuperCall Callable callable, @AllArguments Object[] args) throws Exception { 
  3.     long start = System.currentTimeMillis(); 
  4.     Object resObj = null
  5.     try { 
  6.         resObj = callable.call(); 
  7.         return resObj; 
  8.     } finally { 
  9.         System.out.println("方法名称:" + method.getName()); 
  10.         System.out.println("入参个数:" + method.getParameterCount()); 
  11.         for (int i = 0; i < method.getParameterCount(); i++) { 
  12.             System.out.println("入参 Idx:" + (i + 1) + " 类型:" + method.getParameterTypes()[i].getTypeName() + " 内容:" + args[i]); 
  13.         } 
  14.         System.out.println("出参类型:" + method.getReturnType().getName()); 
  15.         System.out.println("出参结果:" + resObj); 
  16.         System.out.println("方法耗时:" + (System.currentTimeMillis() - start) + "ms"); 
  17.     } 

这个就是使用 Byte-Buddy 可以采集的信息,你可以通过注解入参,获取到一个方法的全部信息。方法名称、入参个数、入参类型和内容、出参类型和结果以及还能计算方法执行耗时。

四、IDEA 插件开发

关于 IDEA 插件开发的知识内容较多,可以从GitHub搜索一些资料和查阅官方文档:https://plugins.jetbrains.com/docs/intellij/gradle-build-system.html?from=jetbrains.org

此处演示案例关于插件开发的内容比较简单,主要是继承com.intellij.execution.impl.DefaultJavaProgramRunner,Override doExecute 方法,添加自己需要的内容即可。

这部分添加的内容核心就是在程序启动时添加我们的字节码插桩程序,如下:

  1. @Override 
  2. protected RunContentDescriptor doExecute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment env) throws ExecutionException { 
  3.     JavaParameters parameters = ((JavaCommandLine) state).getJavaParameters(); 
  4.     // 信息获取 
  5.     PsiFile psiFile = env.getDataContext().getData(LangDataKeys.PSI_FILE); 
  6.     String packageName = ((PsiJavaFileImpl) psiFile).getPackageName(); 
  7.     // 添加字节码插装 
  8.     ParametersList parametersList = parameters.getVMParametersList(); 
  9.     parametersList.add("-javaagent:" + this.getClass().getResource("/").getPath().substring(1) + "ProjectProbe.jar=" + packageName); 
  10.     return super.doExecute(state, env); 

此处最核心的就是 -javaagent 把 ProjectProbe.jar 工程探针程序的Jar包加载进去。其他的就是一些关于 PsiFile API 的使用,感兴趣可以阅读官方文档中的介绍。

五、效果演示

安装插件

安装插件就和我们正常安装一样,不过目前这个插件在开发阶段,所以需要本地安装。

运行效果

六、总结

 

 

来源: bugstack虫洞栈内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯