在A Guide to Java Bytecode Manipulation with ASM的帮助下,我试图弄清楚ASM是如何工作的。我按照教程为 Integer 类创建了一个“额外”静态字段。这是 Instrumentation 类的简化逻辑:
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, final byte[] buffer) {
if (className.equals("ClassX")) {
var reader = new ClassReader(bytes);
var writer = new ClassWriter(reader, 0);
var visitor = new ClassVisitor() { // simplified
@Override
public void visitEnd() {
if (!isFieldPresent) {
var fv = cv.visitField(ACC_PUBLIC + ACC_STATIC, "aNewBooleanField", BOOLEAN_TYPE.toString(), null, true);
if (fv != null) fv.visitEnd();
}
cv.visitEnd();
}
};
reader.accept(visitor, 0);
return writer.toByteArray();
}
return buffer;
}
});
}
我用maven打包了ASM代码;现在我正在尝试运行它,但我不知道如何使用它。我希望我应该能够做到这样的事情:
public static void main(String[] args) {
System.out.println(ClassX.aNewBooleanField);
}
这当然不会编译,因为编译器不知道额外的字段。我尝试按照教程的建议添加 java agent¹,但我也不明白。编译器如何知道在运行时运行的进程(代理)?
所以底线问题是,我如何使用 ASM 操纵代码?
¹
-javaagent:"/<path>/.m2/repository/org/example/try-asm/1.0-SNAPSHOT/try-asm-1.0-SNAPSHOT.jar"
如问题所述,编译器确实不知道对类的字节码所做的修改。因此,您不能直接调用
ClassX.aNewBooleanField
。因此你需要回归反思:
var modifiedClass = Class.forName("ClassX");
var field = modifiedClass.getField("aNewBooleanField");
System.out.println(field.getBoolean(null));
您现在可以编译您的代码,您可以使用 java 代理运行它,上面的代码将打印出
true
值!