几天前我开始学习Java Agent。但文档不是很好,像我这样的初学者正在努力理解基础知识。我创建了一个基本的乘数类,并使用eclipse将其导出到runnable jar。这是代码段。
主要jar文件:
public class Multiplier {
public static void main(String[] args) {
int x = 10;
int y = 25;
int z = x * y;
System.out.println("Multiply of x*y = " + z);
}
}
现在我想从代理操纵x的值。我尝试像这样创建Agent类
代理:
package myagent;
import org.objectweb.asm.*;
import java.lang.instrument.*;
public class Agent {
public static void premain(final String agentArg, final Instrumentation inst) {
System.out.println("Agent Started");
int x_modified = 5;
//Now How to push the new value (x_modified) to the multiplier class?
//I know I have to use ASM but can't figure it out how to do it.
//Result should be 125
}
}
我的问题
如何使用ASM将代理类的x值设置为乘数类? 结果应为125。
答案 0 :(得分:1)
您已在main方法中声明了x。所以它的范围是本地的。这就是为什么你不能从任何其他类改变x的值。
答案 1 :(得分:0)
要使用ASM,您需要在自定义ClassWriter中使用自定义CodeWriter,并将其传递给ClassReader。 http://asm.ow2.org/doc/tutorial.html这将允许您访问每种方法的代码中的所有说明。
特别需要覆盖visitIntInsn
方法,以便当您在BIPUSH
中看到第一条main
指令时,您可以将值10替换为您选择的值。< / p>
ClassWriter的输出是一个byte [],您的Instrumentation将返回而不是原始代码,此时x
将是您在代码中所做的任何值。
答案 2 :(得分:0)
首先,您的代理人必须做的是registering a ClassFileTransformer
。第一件事,类文件转换器应该在其transform
方法中执行,检查参数以确定当前请求是否与我们感兴趣的类有关,如果不是则立即返回。
如果我们在要转换的类中,我们必须处理传入的类文件字节以返回一个新的字节数组。您可以使用ASM的ClassReader
处理传入的字节并将其链接到ClassWriter
以生成新数组:
import java.lang.instrument.*;
import java.security.ProtectionDomain;
import org.objectweb.asm.*;
public class ExampleAgent implements ClassFileTransformer {
private static final String TRANSFORM_CLASS = "Multiplier";
private static final String TRANSFORM_METHOD_NAME = "main";
private static final String TRANSFORM_METHOD_DESC = "([Ljava/lang/String;)V";
public static void premain(String arg, Instrumentation instrumentation) {
instrumentation.addTransformer(new ExampleAgent());
}
public byte[] transform(ClassLoader loader, String className, Class<?> cl,
ProtectionDomain pd, byte[] classfileBuffer) {
if(!TRANSFORM_CLASS.equals(className)) return null;
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw = new ClassWriter(cr, 0);
cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(
access, name, desc, signature, exceptions);
if(name.equals(TRANSFORM_METHOD_NAME)
&& desc.equals(TRANSFORM_METHOD_DESC)) {
return new MethodVisitor(Opcodes.ASM5, mv) {
@Override
public void visitIntInsn(int opcode, int operand) {
if(opcode == Opcodes.BIPUSH && operand == 10) operand = 5;
super.visitIntInsn(opcode, operand);
}
};
}
return mv;
}
}, 0);
return cw.toByteArray();
}
}
请注意,将ClassWriter
传递给我们的自定义ClassVisitor
的构造函数,并将MethodVisitor
调用返回的super.visitMethod
传递给MethodVisitor
个构造函数,我们启用一个默认情况下重现原始类的链接;我们未覆盖的所有方法都将委托给指定的ClassWriter
/ MethodVisitor
再现遇到的工件。与the tutorial about ASM’s event model比较。
上面的示例通过将ClassReader
实例传递给ClassWriter
的构造函数来启用优化。这样,只需做一些小改动就可以提高班级的工作效率,就像我们在这里做的那样。
当我们处于“热门”方法并覆盖visitMethod
以更改所需指令时,关键部分是覆盖MethodVisitor
以返回我们的自定义visitIntInsn
。请注意这些方法在不改变行为时如何委托给super
调用,就像我们没有覆盖的方法一样。