Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何通过插入/ASM来实例化不同的类_Java_Instrumentation_Java Bytecode Asm_Bytecode Manipulation - Fatal编程技术网

Java 如何通过插入/ASM来实例化不同的类

Java 如何通过插入/ASM来实例化不同的类,java,instrumentation,java-bytecode-asm,bytecode-manipulation,Java,Instrumentation,Java Bytecode Asm,Bytecode Manipulation,我正在尝试在javaagent(sun/misc/URLClassPath)中使用ASM,将其转换为从它继承并覆盖所有方法的另一个(fommil/URLClassPath)。我知道我正在重新转换的目标类(java/net/URLClassLoader)是唯一创建sun/misc/URLClassPath的对象,并且仅在其构造函数中 基本思想如下: @Override public MethodVisitor visitMethod(int access,

我正在尝试在javaagent(
sun/misc/URLClassPath
)中使用ASM,将其转换为从它继承并覆盖所有方法的另一个(
fommil/URLClassPath
)。我知道我正在重新转换的目标类(
java/net/URLClassLoader
)是唯一创建
sun/misc/URLClassPath
的对象,并且仅在其构造函数中

基本思想如下:

@Override
public MethodVisitor visitMethod(int access,
                                 String name,
                                 String desc,
                                 String signature,
                                 String[] exceptions) {
    MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions);

    return new MethodVisitor(Opcodes.ASM5, visitor) {
        @Override
        public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
            if (opcode == Opcodes.INVOKESPECIAL && "sun/misc/URLClassPath".equals(owner) && "<init>".equals(name)) {
                super.visitMethodInsn(opcode, "fommil/URLClassPath", name, desc, itf);
            } else {
                super.visitMethodInsn(opcode, owner, name, desc, itf);
            }
        }
    };
}
@覆盖
公共方法访问者访问方法(int访问,
字符串名,
字符串描述,
字符串签名,
字符串[]异常){
MethodVisitor=super.visitMethod(访问、名称、描述、签名、异常);
返回新方法访问者(操作码.ASM5,访问者){
@凌驾
public void visitMethodInsn(int操作码、字符串所有者、字符串名称、字符串描述、布尔itf){
if(opcode==Opcodes.INVOKESPECIAL&&“sun/misc/URLClassPath”.equals(所有者)&&&&.”.equals(名称)){
super.visitMethodInsn(操作码,“fommil/URLClassPath”、名称、说明、itf);
}否则{
超级访问方法(操作码、所有者、名称、描述、itf);
}
}
};
}
我可以在
fommil/URLClassPath
的构造函数中放置
println
,并看到它正在被构造

但是,
fommil.URLClassPath
的方法都没有被调用。只调用超类上的方法

即使我更改了上述代码,这样不仅
invokespecial
/
,而且对
URLClassPath
的所有调用都被重写,以便它们的
invokevirtual
指向我的类,我的方法仍然不会被调用。我甚至对
URLClassLoader
的所有内部类都尝试过这样做

那么,为什么
invokevirtual
s即使在重写方法时也找不到它们呢?我正在做的事情——改变正在构建的事物的类型——根本不可能吗?如果是这样,有人能解释一下原因吗

我知道检测核心JDK类是非常邪恶的,但坦率地说,我没有太多的选择

剩下的唯一一件事就是对所有试图实例化
URLClassLoader
的类进行指令插入,让它们插入内部
ucp
字段,并用我的实现替换它。

我明白了

考虑一下这个简单的代码

import java.util.*;    
class Baz {
    public void baz() {
        List list = new ArrayList();
    }
}
产生

   0: new           #2                  // class java/util/ArrayList
   3: dup
   4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
   7: astore_1
   8: return
   0: new           #2                  // class java/util/LinkedList
   3: dup
   4: invokespecial #3                  // Method java/util/LinkedList."<init>":()V
   7: astore_1
   8: return
产生

   0: new           #2                  // class java/util/ArrayList
   3: dup
   4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
   7: astore_1
   8: return
   0: new           #2                  // class java/util/LinkedList
   3: dup
   4: invokespecial #3                  // Method java/util/LinkedList."<init>":()V
   7: astore_1
   8: return

您使用的是invokespecial,它用于构造函数(这是正确的),而不是invokevirtual,它用于可以被重写的方法。@PeterLawrey再次阅读代码,我知道您在说什么。这不是问题所在。我没有说是,这就是我发表评论的原因。我怀疑URLCLassLoader是在您的转换开始之前被调用的。必须加载转换器正在使用的类。这是一个重传。注意这一点:“我可以在fommil/URLClassPath的构造函数中放置一个println,并看到它正在被构造!”它是否正在所有需要使用它的地方被构造。e、 假设JVM创建一个URLClassLoader来加载所有基本类和转换器。在某些代码被更改后,您的URLClassLoader会更改类型,还是继续使用?