2010-11-21 10 views
5

Contexto: Una nueva clase, por ejemplo, Bar, se inyecta en la JVM en tiempo de ejecución. Esta clase pertenece a un paquete decir com.foo. Una referencia a esta clase se inyecta en otra clase que pertenece al mismo paquete. La nueva clase puede tener un nombre diferente cada vez que se carga, por lo que no se puede especificar como parte de ningún archivo de configuración, p. no se puede especificar en build.xml para incluirlo como parte de un archivo jar.configuración del classpath para una clase recientemente inyectada

Issue: En el tiempo de carga de clase, jvm arroja un error - java Resultado 1. Aunque no puedo determinar de manera concluyente la causa raíz, parece que la clase recién inyectada no está siendo encontrada por el cargador de clases. El servidor se ejecutó en modo detallado que muestra la lista de clases cargadas por la JVM y esta clase recién inyectada se ve cargada.

Pregunta: ¿La clase recién inyectada ya está en el classpath? Si no, ¿cómo configurarlo?

[Editar] - agregando un código a la pregunta.

Segmento de código - 1: este segmento de código siguiente se llama desde el método PreMain - El agente de JVM llamará al método Premain e inyectará la referencia de instrumentación en tiempo de ejecución. El método Premain inyecta 1 nueva clase - Barra - y 1 referencia a esta nueva clase desde un método - devuelve ABool() - en una clase existente - 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 
} 

Código Sement 2: El returnsABool método() necesita ser byte-inyectados con el líneas de comentarios que se muestran abajo. El código para insertar byte esto también se llama desde el método 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; 
    } 
} 

Byte inyección de código para ExistingClass - hace usando la biblioteca 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(); 
} 
+0

¿Cómo, específicamente, se está "inyectando" la clase? ¿Se crea y carga dinámicamente por el cargador de clases? –

+0

Algún código de Java sería útil, de lo contrario es muy difícil ayudarte. Además, tal vez esta pregunta sea útil: http://stackoverflow.com/q/4210346/74694 –

+3

Muestre un ejemplo mínimo que demuestre el problema que tiene. –

Respuesta

1

yo sospecha que tiene algún problema con la generación de código de bytes, el siguiente código ASM funciona para mí:

 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(); 

También tenga en cuenta que:

  • la forma en que está comparando cadenas más probable conducir a problemas, debe utilizar str.equals(str2)
  • va a sustituir todo el método, en lugar de inyectar el código personalizado en el principio (sus comentarios parecen indicar que desea inyectar , en lugar de reemplazar)
+0

Fantástico - Gracias Neeme - esto (uso de iguales) resolvió el problema - lección aprendida de la manera difícil! –

+0

Solo para completar la respuesta, parece que las clases inyectadas en tiempo de ejecución ya están en la ruta de clase. –

+0

¿Qué herramienta usaste para generar el código anterior? –

Cuestiones relacionadas