Java 探针的原理

Java 探针的原理其实核心就四个字:
字节码增强

一、Java 探针的核心机制

Java 探针一般是通过 Java Agent 技术实现的,依赖于 JVM 提供的 Instrumentation 接口。

1. Java Agent

  • JVM 启动时,可以通过 -javaagent:xxx.jar 加载一个探针 Jar 包。
  • 这个 Jar 包里需要有一个入口类,并实现 premain(String args, Instrumentation inst) 方法。
  • JVM 启动时会先调用 premain,然后再运行你的应用 main 方法。

2. Instrumentation

  • Instrumentation 提供了操作 类加载 的能力。
  • 可以注册 ClassFileTransformer,在类被加载进 JVM 时,修改它的字节码。
  • 借助 ASMJavassist 等字节码工具,就能在目标类的方法前后插入代码。

3. 探针的运行逻辑

  1. JVM 启动时加载探针 Jar。
  2. 探针注册一个 Transformer。
  3. 当某个类加载时,探针修改它的字节码(比如在方法入口/出口插入埋点)。
  4. 应用运行时,探针代码也随之运行,实现监控/拦截/增强。

二、Java 探针常见应用

  1. 性能监控 (APM)

    • 拦截 HTTP 请求方法,记录调用链。
    • 拦截 JDBC,记录 SQL 和执行时间。
    • 采集 JVM 指标(GC、内存、线程)。
  2. 安全防护 (RASP)

    • 在 Servlet 的 doFilter 拦截请求,检测 SQL 注入/XSS。
    • FileInputStreamSocket 等 API 上插入检测逻辑。
  3. 诊断工具

    • Arthas、BTrace 这些工具就是探针。
    • 在运行时动态 attach 探针,修改类行为,不用重启应用。

三、简单示例:打印方法执行时间的探针

Agent.java

import java.lang.instrument.Instrumentation;

public class Agent {
    public static void premain(String args, Instrumentation inst) {
        System.out.println("Java Agent Loaded!");
        inst.addTransformer(new MyTransformer());
    }
}

MyTransformer.java(用 Javassist 修改字节码)

import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
import javassist.*;

public class MyTransformer implements ClassFileTransformer {
    @Override
    public byte[] transform(ClassLoader loader, String className,
                            Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
                            byte[] classfileBuffer) {
        if ("com/example/DemoService".equals(className)) {
            try {
                ClassPool pool = ClassPool.getDefault();
                CtClass ctClass = pool.get("com.example.DemoService");
                CtMethod method = ctClass.getDeclaredMethod("process");

                method.addLocalVariable("start", CtClass.longType);
                method.insertBefore("start = System.currentTimeMillis();");
                method.insertAfter("System.out.println(\"耗时: \" + (System.currentTimeMillis()-start) + \"ms\");");

                return ctClass.toBytecode();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return classfileBuffer;
    }
}

运行时:

java -javaagent:my-agent.jar -jar app.jar

这样 DemoService.process() 方法就会自动打印耗时。

四、总结

  • Java 探针原理 = JVM 的 Instrumentation API + 字节码增强技术

  • 关键点

    • 通过 -javaagent 在 JVM 启动时加载。
    • 修改类字节码,在方法前后插入探针逻辑。
    • 适合做性能监控、安全防护、诊断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

思静鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值