一、前言

一套系统是否稳定运行,取决于它的运行健康度,而这包括;调用量、可用率、响应时长以及服务器性能等各项指标的一个综合值。并且在系统出现异常问题时,可以抓取整个业务方法执行链路并输出;当时的入参、出参、异常信息等等。当然还包括一些JVM、Redis、Mysql的各项性能指标,以用于快速定位并解决问题。

那么要做到这样的事情有什么监控方案呢,这里面的做法比较多。比如:

:::info

  • 最简单粗暴的可能就是硬编码在方法中,收取执行耗时以及出入参和异常信息。但这样的成本实在太大,而且有一些不可预估的风险。
  • 可以选择切面方式做一套统一监控的组件,相对来说还是好一些的。但也需要硬编码,同时维护成本不低。
  • 市面上对于这样的监控其实是有整套的非入侵监控方案的,比如;Google DapperZipkin等都可以实现,他们都是基于探针技术非入侵的采用字节码增强的方式进行监控。 :::

那么这样非入侵的探针方式是怎么实现的呢?如何去做方法的字节码增强

在字节码增强方面有三个框架;ASMJavassistByteCode,各有优缺点按需选择。这在我们之前的字节码编程文章里也有所提到。本文主要讲解关于 ASM 方式的字节码增强,接下来的案例会逐步讲解一个给方法添加 TryCatch 块,用于采集异常信息以及正常的出参结果的流程。

二、系统环境

  1. jdk1.8.0
  2. asm-commons 6.2.1

三、技术目标

通过 ASM 字节码增强技术,使用指令码将方法修改为我们想要的效果。这部分原本需要使用 JavaAgent 技术,在工程启动加载时候进行修改字节码。这里为了将关于字节码核心内容展示出来,通过加载类名称获取字节码进行修改。

修改之前的代码:

  1. public Integer strToNumber(String str) {
  2. return Integer.parseInt(str);
  3. }

使用ASM技术修改之后的代码:

  1. public Integer strToNumber(String str) {
  2. try {
  3. Integer var2 = Integer.parseInt(str);
  4. MethodTest.point("org.itstack.test.MethodTest$Test.strToNumber", var2);
  5. return var2;
  6. } catch (Exception var3) {
  7. MethodTest.point("org.itstack.test.MethodTest$Test.strToNumber", var3);
  8. throw var3;
  9. }}

从修改前到修改后,可以看到。有如下几点修改;

  1. 返回值赋值给新的参数,并做了输出
  2. 把方法包裹在一个 TryCatch 中,并将异常也做了输出

好!如果你有很敏锐的嗅觉,或者很多小问号。那么你是否会想到如果使用到你自己的业务中,是不是就可以做一套非入侵的监控系统了?

四、实现过程

字节码增强的过程乍一看还是比较麻烦的,如果你没有阅读过JVM虚拟机规范等相关书籍,确实很不好理解。但是也就是这部分不那么容易理解的知识,才是你后续价值的体现。