乐趣区

关于java:方案设计基于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 代理或在构建过程中手动更改类。

  • 无需了解字节码指令,即可应用简略的 API 就能很容易操作字节码,管制类和办法。
  • 已反对 Java 11,库轻量,仅取决于 Java 字节代码解析器库 ASM 的访问者 API,它自身不须要任何其余依赖项。
  • 比起 JDK 动静代理、cglib、Javassist,Byte Buddy 在性能上具备肯定的劣势。

1. 办法入口

public static void premain(String agentArgs, Instrumentation inst) {AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {
        return builder
                .method(ElementMatchers.any()) // 拦挡任意办法
                .intercept(MethodDelegation.to(MonitorMethod.class));
    };
    new AgentBuilder
            .Default()
            .type(ElementMatchers.nameStartsWith(agentArgs)) 
            .transform(transformer)
            .installOn(inst);
}

如果你接触过 Javaagent 开发,那么对于 premain 会比拟相熟。如果不分明你能够把它了解为,它是程序启动的时的办法入口,你能够从这个入口中拦挡到你须要的办法,之后对它进行字节码加强。其实也就是动静写代码,在办法中增加你的代码,来收集办法信息。

2. 采集信息

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

这个就是应用 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 办法,增加本人须要的内容即可。

这部分增加的内容外围就是在程序启动时增加咱们的字节码插桩程序,如下:

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

此处最外围的就是 -javaagentProjectProbe.jar 工程探针程序的 Jar 包加载进去。其余的就是一些对于 PsiFile API 的应用,感兴趣能够浏览官网文档中的介绍。

五、成果演示

装置插件

  • 装置插件就和咱们失常装置一样,不过目前这个插件在开发阶段,所以须要本地装置。

运行成果

  • 上图就是运行成果的案例演示,咱们把运行时接口的信息残缺的输入到控制台。
  • 在理论应用的过程中,会把这部分信息传回服务端,由服务端剖析解决后,展现在页面上。

六、总结

  • 基于 IDEA 插件和字节码插桩技术,能做的性能实现还有很多。本文仅仅是其中一种研发到测试痛点的解决方案,如果感兴趣能够一起深入研究。
  • 当你看到这样的案例当前,心愿能给你的是并不一定所有的技术点都是为了面试造火箭对话的。当你真的把它落地当前,才会懂的本人须要很多常识。
  • 本文没有太过多的介绍插件开发和字节码技术,如果对字节码编程感兴趣,能够在公众号:bugstack 虫洞栈 ,回复 字节码编程 。全书 11 万 7 千字,20 个章节涵盖三个字节码框架(ASM、Javassist、Byte-budy) 和 JavaAgent 应用并附带整套案例源码!

七、系列举荐

  • 数学,离一个程序员有多近?
  • 一次代码评审,差点过不了试用期!
  • 《Java 面经手册》PDF,全书 5 章 29 节,417 页 11.5 万字,完稿 & 发版!
  • 工作两年简历写成这样,谁要你呀!
  • 工作 3 年,看啥材料能月薪 30K?

博客:https://bugstack.cn
GitHub:https://github.com/fuzhengwei/CodeGuide/wiki

退出移动版