我試圖調用一個靜態方法,每當一個對象被分配,但遇到問題。我已經將我的代碼縮減爲小型工作示例。NoClassDefFoundError通過檢測字節代碼調用類的靜態方法
MemorySnifferAgent.java
public class MemorySnifferAgent {
public static void premain(String agentArguments, Instrumentation instrumentation) {
Callback.main(); //Make sure the class is loaded ?
instrumentation.addTransformer(new MemoryAllocationTransformer());
}
}
MemoryAllocationTransformer.java
public class MemoryAllocationTransformer implements ClassFileTransformer {
public byte[] instrumentByteCode(byte[] bytecode) {
ClassReader reader = new ClassReader(bytecode);
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
CustomClassReader customVisitor = new CustomClassReader(Opcodes.ASM4, writer);
reader.accept(customVisitor, 0);
return writer.toByteArray();
}
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] bytes = instrumentByteCode(classfileBuffer);
return bytes;
}
}
CustomClassReader.java
public class CustomClassReader extends ClassVisitor {
public CustomClassReader(int api, ClassWriter classWriter) {
super(api, classWriter);
}
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodVisitor methodWritter = super.visitMethod(access, name, desc, signature, exceptions);
return new CustomMethodWritter(api, name, methodWritter);
}
}
CustomMethodWritter.java
class CustomMethodWritter extends MethodVisitor {
String name;
public CustomMethodWritter(int i, String name, MethodVisitor methodWriter) {
super(i, methodWriter);
this.name = name;
}
@Override
public void visitTypeInsn(int opcode, String type) {
super.visitTypeInsn(opcode, type);
if (opcode == Opcodes.NEW) {
super.visitMethodInsn(Opcodes.INVOKESTATIC, "com/chasingnanos/Callback", "onAllocation", "()V", false);
}
}
}
注:
- 我意識到,竊聽到所有的分配需要挖掘出各種新*操作碼和反射API的
- super.visitMethodInsn(Opcodes.INVOKESTATIC, 「COM/chasingnanos /回撥」, 「onAllocation」 「()V」,false);似乎是問題所在。雖然我無法找到問題所在。
道歉,如果這是一個非常基本的問題。我是字節碼操作的新手。
錯誤,我得到:
java.lang.NoClassDefFoundError - 克拉斯: '爪哇/郎/ NoClassDefFoundError的'
你是對的!看起來premain是由 [email protected]調用的,它看起來不錯,但是通過引導加載程序調用變換。我添加了下面的代碼片段以進行轉換並且工作正常。 (loader == null){ System.out.println 返回null; } else System.out.println(「Transformed by」+ loader.toString()+「loader」); 在AppClassLoader之後爲什麼要調用bootstap加載器的任何想法? – KodeWarrior
我不確定我是否收到您的問題。是否回答「因爲所有課程都是懶惰地(按需求)加載」滿足你?我也想提醒你,在一個複雜的應用程序,做自己的'基於ClassLoader'魔法(如網絡/應用程序容器)只檢查'裝載機== null'可能是不夠的 – SergGr
我知道,類懶惰地加載,但我不確定引導程序被調用。我認爲它在第一次調用AppClassLoader之前只調用一次。 – KodeWarrior