2010-11-21 6 views
5

コンテキスト: 実行時に、Barという新しいクラスがJVMに注入されます。このクラスはcom.fooというパッケージに属します。 このクラスへの参照は、同じパッケージに属する別のクラスに注入されます。 新しいクラスは読み込まれるたびに別の名前を持つ可能性があります。したがって、これは設定ファイルの一部として指定することはできません。 jarファイルの一部としてbuild.xmlに指定することはできません。新しく挿入されたクラスのクラスパスを設定する

問題: クラスロード時に、jvmがエラーをスローします - java結果1.根本的な原因を突き止めることはできませんが、新しく挿入されたクラスがクラスローダーによって見つからないようです。 サーバーは冗長モードで実行され、JVMによってロードされたクラスのリストが表示され、この新しく挿入されたクラスがロードされたと見なされます。

質問: 新しく注入されたクラスは既にクラスパスにありますか?それを設定する方法でない場合は?

[編集] - 質問にいくつかのコードを追加します。

コードセグメント - 1:このコードセグメントは、PreMainメソッドから呼び出されます。 - Premainメソッドは、JVMエージェントによって呼び出され、実行時に計測リファレンスを注入します。 Premainメソッドは、1つの新しいクラス(Bar)と既存のクラス(ExistingClass)のreturnsABool()から、この新しいクラスへの参照を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:方法returnsABool()は以下に示すコメント 線とバイト注入する必要があります。これをバイトインジェクトするコードは、PreMainメソッドからも呼び出されます。 ExistingClassため

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(); 
} 
+0

どのように具体的には、クラスは "注射"されていますか?それは動的に作成され、クラスローダーによって読み込まれますか? –

+0

いくつかのJavaコードが役に立ちます。そうでなければ、あなたを助けることは非常に困難です。また、おそらくこの質問は役に立ちます:http://stackoverflow.com/q/4210346/74694 –

+3

あなたが持っている問題を示す最小限の例を示してください。 –

答えて

1

を使用して行われ、以下の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)
  • を使用する必要があります、代わりに置き換える)
+0

ファンタスティック - ありがとうNeeme - これは(等号の使用)問題を解決しました - レッスンは難しい方法を学んだ! –

+0

答えを完了するだけで、実行時に注入されたクラスがすでにクラスパスにあるように見えます。 –

+0

上記のコードを生成するためにどのツールを使用しましたか? –

関連する問題