☰
HoRain云--Java字节码增强:ASM、Byte Buddy与Java Agent
2026/10/14 13:03:53 网站建设 项目流程

字节码增强是Java黑魔法,APM监控、AOP、Mock框架都依赖它。本文讲解ASM、Byte Buddy、Javassist和Java Agent,并实战写一个无侵入监控。

一、字节码基础

Java源码编译为.class,JVM加载并执行。字节码是JVM的指令集。

bash

复制

下载

javap -c -p MyClass.class

java

复制

下载

public class Hello { public static void main(String[] args) { System.out.println("Hello"); } }

字节码:

text

复制

下载

0: getstatic #7 // System.out 3: ldc #13 // "Hello" 5: invokevirtual #15 // println 8: return

二、ASM

ASM直接操作字节码,性能高但API复杂。

java

复制

下载

ClassReader reader = new ClassReader(bytes); ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); ClassVisitor visitor = new ClassVisitor(Opcodes.ASM9, writer) { @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); if ("target".equals(name)) { return new MethodVisitor(Opcodes.ASM9, mv) { @Override public void visitCode() { mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitLdcInsn("方法开始"); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); super.visitCode(); } }; } return mv; } }; reader.accept(visitor, 0); byte[] newBytes = writer.toByteArray();

三、Byte Buddy

API友好,适合快速开发。

java

复制

下载

Class<?> dynamicType = new ByteBuddy() .subclass(Object.class) .name("com.example.Hello") .method(ElementMatchers.named("toString")) .intercept(FixedValue.value("Hello World")) .make() .load(Hello.class.getClassLoader()) .getLoaded(); Object instance = dynamicType.getDeclaredConstructor().newInstance(); System.out.println(instance); // Hello World

拦截已有方法:

java

复制

下载

new ByteBuddy() .redefine(UserService.class) .method(named("save")) .intercept(MethodDelegation.to(TimingInterceptor.class)) .make() .load(UserService.class.getClassLoader());

java

复制

下载

public class TimingInterceptor { @RuntimeType public static Object intercept(@Origin Method method, @SuperCall Callable<?> callable) throws Exception { long start = System.currentTimeMillis(); try { return callable.call(); } finally { System.out.println(method.getName() + " 耗时: " + (System.currentTimeMillis() - start) + "ms"); } } }

四、Javassist

源码级API,适合简单场景。

java

复制

下载

ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.example.UserService"); CtMethod m = cc.getDeclaredMethod("save"); m.insertBefore("System.out.println(\"before\");"); m.insertAfter("System.out.println(\"after\");"); cc.toClass();

五、Java Agent

Agent可在JVM启动时或运行时增强类。

5.1 启动时Agent

java

复制

下载

public class MyAgent { public static void premain(String args, Instrumentation inst) { inst.addTransformer(new MyTransformer()); } }

META-INF/MANIFEST.MF:

text

复制

下载

Premain-Class: com.example.MyAgent Can-Redefine-Classes: true Can-Retransform-Classes: true

启动:

bash

复制

下载

java -javaagent:myagent.jar -jar app.jar
5.2 运行时Attach

java

复制

下载

public class AgentMain { public static void agentmain(String args, Instrumentation inst) { inst.addTransformer(new MyTransformer(), true); for (Class<?> clazz : inst.getAllLoadedClasses()) { if (clazz.getName().startsWith("com.example")) { try { inst.retransformClasses(clazz); } catch (Exception e) {} } } } }

Attach:

java

复制

下载

VirtualMachine vm = VirtualMachine.attach(pid); vm.loadAgent("myagent.jar"); vm.detach();

六、实战:方法耗时监控Agent

java

复制

下载

public class TimingTransformer implements ClassTransformer { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain pd, byte[] classfileBuffer) { if (!className.startsWith("com/example/service")) { return classfileBuffer; } return new ByteBuddy() .redefine(new ByteArrayClassLoader(loader, classfileBuffer)) .method(isPublic().and(not(isStatic()))) .intercept(MethodDelegation.to(TimingInterceptor.class)) .make() .getBytes(); } }

七、应用场景

  1. APM监控:SkyWalking、Pinpoint

  2. AOP:Spring AOP(CGLIB)

  3. Mock:Mockito、JMockit

  4. 热部署:JRebel

  5. 性能分析:async-profiler

  6. 安全:RASP

八、总结

字节码增强是Java进阶技能。ASM性能高但复杂,Byte Buddy易用,Java Agent实现无侵入。掌握它们,能开发监控、诊断、框架类工具。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询