java - 为新注入(inject)的类设置类路径

标签 java classpath code-injection

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

问题: 在类加载时,jvm 抛出错误 - java Result 1。虽然我不能最终确定根本原因,但看起来新注入(inject)的类没有被类加载器找到。 服务器以详细模式运行,显示 JVM 加载的类列表,并且可以看到已加载这个新注入(inject)的类。

问题: 新注入(inject)的类是否已经在类路径中?如果不是怎么设置?

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

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

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
}

代码段 2:方法 returnsABool() 需要用注释进行字节注入(inject) 线如下所示。字节注入(inject)的代码也是从 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;
    }
}

ExistingClass 的字节代码注入(inject) - 使用 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)
  • 您正在替换整个方法,而不是在开始时注入(inject)您的自定义代码(您的评论似乎表明您想要注入(inject),而不是替换)

关于java - 为新注入(inject)的类设置类路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4239147/

相关文章:

java - 详尽地讲,Java 是如何确定您的类路径的?

javac 多个命令选项

node.js - node.js 安全/转义中的 child_process 生成

java - 通过代码处理 JDialog,不要让用户关闭它

java - 在java中乘以 double ?

支持 AES-NI 的 Java SSL 提供商

Java-方法似乎在第二次调用时跳过了一个步骤

build - 我的gradle配置在构建期间未使用正确的类路径

android - Roboguice 注入(inject)和 Provider 类

maven - HelloWorld EJB 依赖注入(inject)