Java 为新注入的类设置类路径

Java 为新注入的类设置类路径,java,classpath,code-injection,Java,Classpath,Code Injection,背景: 一个新类(比如Bar)在运行时被注入JVM。这个类属于一个包,比如com.foo。 对该类的引用被注入到属于同一包的另一个类中。 新类在每次加载时可能有不同的名称-因此不能将其指定为任何配置文件的一部分-例如,不能在build.xml中指定作为jar文件的一部分 问题: 在类加载时,jvm抛出一个错误-java结果1。尽管我无法确定根本原因,但类装入器似乎没有找到新注入的类。 服务器以详细模式运行,该模式显示JVM加载的类的列表,并且这个新注入的类被加载 问题: 新注入的类是否已在类路径

背景: 一个新类(比如Bar)在运行时被注入JVM。这个类属于一个包,比如com.foo。 对该类的引用被注入到属于同一包的另一个类中。 新类在每次加载时可能有不同的名称-因此不能将其指定为任何配置文件的一部分-例如,不能在build.xml中指定作为jar文件的一部分

问题: 在类加载时,jvm抛出一个错误-java结果1。尽管我无法确定根本原因,但类装入器似乎没有找到新注入的类。 服务器以详细模式运行,该模式显示JVM加载的类的列表,并且这个新注入的类被加载

问题: 新注入的类是否已在类路径中?如果没有,如何设置

[编辑]-为问题添加一些代码

代码段-1:下面的代码段是从PreMain方法调用的-PreMain方法将由JVM代理调用,并将在运行时注入插装引用。Premain方法从现有类ExistingClass中的方法ReturnsBool()中注入1个新类Bar和1个对此新类的引用

public static void premain(String agentArgs, Instrumentation inst) {

        // 1. Create and load the new class - Bar
        String className = "Bar";
        byte [] b = getBytesForNewClass();
        //override classDefine (as it is protected) and define the class.
        Class clazz = null;
        try {
          ClassLoader loader = ClassLoader.getSystemClassLoader();
          Class cls = Class.forName("java.lang.ClassLoader");
          java.lang.reflect.Method method =
            cls.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class, int.class });
          // protected method invocation
          method.setAccessible(true);
          try {
            Object[] args = new Object[] { className, b, new Integer(0), new Integer(b.length)};
            clazz = (Class) method.invoke(loader, args);
          } finally {
            method.setAccessible(false);
          }
        } catch (Exception e) {
         System.err.println(
            "AllocationInstrumenter was unable to create new class" + e.getMessage());
         e.printStackTrace();
        }

        // 2. Inject some lines of code into the returnsABool method in ExistingClass class that references Bar
        inst.addTransformer(new CustomInstrumenter(), true);

        // end of premain method
}
代码sement 2:方法returnsBool()需要用注释的 行如下所示。也可以从PreMain方法中调用将其注入字节的代码

public class ExistingClass{

    public static boolean returnsABool() {
     // Code within comments is byte-injected, again as part of the pre-main method

     /*
     String str = Bar.get();
     if (str != "someValue") {
      return true;
     }
     */

        return false;
    }
}
现有类的字节码注入-使用asm库完成

{  
    MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);  
    mv.visitCode();  
    Label l0 = new Label();  
    mv.visitLabel(l0);   
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/Bar", "get", "()Ljava/lang/String;");        
    mv.visitLdcInsn("some constant here");   
    Label l1 = new Label();   
    mv.visitJumpInsn(Opcodes.IF_ACMPNE, l1);   
    mv.visitInsn(Opcodes.ICONST_0); Label l2 = new Label();   
    mv.visitJumpInsn(Opcodes.GOTO, l2);   
    mv.visitLabel(l1);   
    mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);   
    mv.visitInsn(Opcodes.ICONST_1); 
    mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {Opcodes.INTEGER});  
    mv.visitInsn(Opcodes.IRETURN);   
    mv.visitMaxs(2, 0);   
    mv.visitEnd();   
}

我怀疑您的字节码生成有问题,以下ASM代码适合我:

        mv.visitCode();
        Label l0 = new Label();
        mv.visitLabel(l0);
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/Bar", "get", "()Ljava/lang/String;");
        Label l1 = new Label();
        mv.visitLdcInsn("some constant here");
        mv.visitJumpInsn(Opcodes.IF_ACMPEQ, l1);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitInsn(Opcodes.ICONST_1);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 1, new Object[] {Opcodes.INTEGER});
        mv.visitInsn(Opcodes.IRETURN);
        mv.visitLabel(l1);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitInsn(Opcodes.ICONST_0);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 1, new Object[] {Opcodes.INTEGER});
        mv.visitInsn(Opcodes.IRETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();
还请注意:

  • 比较字符串的方式很可能会导致问题,您应该使用
    str.equals(str2)
  • 您正在替换整个方法,而不是在开始时注入自定义代码(您的注释似乎表明您要注入,而不是替换)

具体来说,该类是如何“注入”的?它是由类加载器动态创建和加载的吗?一些java代码会很有用,否则很难帮助您。另外,这个问题可能会有帮助:显示一个演示您的问题的最小示例。伯特,是的,这个动态类是由ClassLoader创建和加载的。@crazy horse:您的代码格式不正确,请使用01010101按钮。而且,如果你能说出这段代码的目的,这将是很有帮助的。太棒了-谢谢你Neeme-这(使用equals)解决了这个问题-从艰苦的过程中吸取了教训!为了完成回答,在运行时注入的类似乎已经在类路径中。@crazy horse:我使用了ASM Eclipse插件()并手动调整了生成的代码,使其看起来更像您的代码。