以下示例将检测添加到ClassNotFoundException 的构造函数,并在调用它时执行System.err.println。
我不确定如何从我认为您需要的工具调用回调。
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.security.ProtectionDomain;
import net.bytebuddy.jar.asm.ClassReader;
import net.bytebuddy.jar.asm.ClassVisitor;
import net.bytebuddy.jar.asm.ClassWriter;
import net.bytebuddy.jar.asm.MethodVisitor;
import net.bytebuddy.jar.asm.Opcodes;
public class ClassNotFoundExceptionIntercept {
public static void premain(String agentArgs, Instrumentation inst) throws UnmodifiableClassException {
inst.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader l, String name, Class<?> c, ProtectionDomain d, byte[] b)
throws IllegalClassFormatException {
if ("java/lang/ClassNotFoundException".equals(name)) {
return instrument(b);
}
return b;
}
}, true);
inst.retransformClasses(java.lang.ClassNotFoundException.class);
}
private static byte[] instrument(byte[] originalBytes) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
ClassAdapter adapter = new ClassAdapter(cw);
ClassReader cr = new ClassReader(originalBytes);
cr.accept(adapter, ClassReader.SKIP_FRAMES);
return cw.toByteArray();
}
public static class ClassAdapter extends ClassVisitor implements Opcodes {
public ClassAdapter(ClassVisitor cv) {
super(ASM4, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
String[] exceptions) {
if ("<init>".equals(name)) {
MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
return new Wrapper(mv);
} else {
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
}
}
private static class Wrapper extends MethodVisitor {
public Wrapper(MethodVisitor mv) {
super(Opcodes.ASM4, mv);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;");
mv.visitLdcInsn("Constructor invoked");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
}
}
}
这需要像这样使用 META-INF/MANIFEST.MF 编译成 JAR 文件
Manifest-Version: 1.0
Premain-Class: ClassNotFoundExceptionIntercept
Agent-Class: ClassNotFoundExceptionIntercept
Can-Retransform-Classes: true
Can-Redefine-Classes: true
并使用程序参数-javaagent:/home/adam/agent-example.jar调用
这可以证明可以与吞下异常的测试类一起使用
public class Test {
public static void main(String[] args) {
try {
Class.forName("brexit");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
输出
Constructor invoked
Constructor invoked
Constructor invoked
java.lang.ClassNotFoundException: brexit
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at Test.main(Test.java:9)