2009-08-29 3 views
3

静的解析ツールをサポートするJavaプログラムを計測または監視して、反射的な呼び出し(Method.invoke(。 。)):Javaプログラムがリフレクションを使用してロードするすべてのクラスの名前を見つける

私には静的に必要としない、私は解決策を探しています。このクラスC.理想的

をロードしたクラスローダ、このメソッドが呼び出されたクラスC

1)、および 2) Java Runtime Libraryを変更します。つまり、ロード時の解決策を探しています。ただし、解決策は、すべての呼び出しをキャプチャできる必要があります.Javaランタイムライブラリ自体で発生している呼び出しであっても解決できます。 (私はClassFileTransformerで遊んでいましたが、これはClassFileTransformer自体に依存しないクラスにのみ適用されるようです。特に、ClassFileTransfomerはクラス "Class"には適用されません)。

ありがとう!

答えて

1

プロダクションで実行できるものをお探しですか?または、テスト環境で実行されているアプリケーションを計測するだけで十分ですか?後者の場合、プロファイリングツールの下でアプリケーションを実行することを検討したいかもしれません。私は個人的に使用して、JProfilerを推奨します。これにより、特定のメソッドが呼び出されたときのログのようなアクションを実行するために、トレースを呼び出してトリガーを設定できます。それは、ホストされたプログラムへの変更を必要とせず、Java実行時ライブラリでうまく動作します。オープンソースのツールもありますが、私はそれらの作業を成功させるほどの成功を収めていません。

本番環境で動作するものが必要な場合は、おそらくAspectJ(AOP)を使用して、JavassistまたはCGLibを使用して独自のカスタムClassloaderまたはバイトコード操作を実装することを検討することができます。これは明らかに複雑なソリューションであり、コンパイル時にサポートされていないとうまくいきませんので、状況に応じてプロファイリングツールを実行することをお勧めします。

0

おそらく後のAPIはJVMTIです。 JVMTIを使用すると、MethodEntry、MethodExitなど、JVM内で発生する大多数のイベントのコールバックを登録できます。あなたはそれらのイベントを聞いて、Method.invokeイベントを引き出します。特定のクラスのクラスローダーを取得するAPI呼び出しがあります。しかし、CやC++でツールを書く必要があります。

ここでは、フィルターをjava.lang.reflect.Method.invoke呼び出しから取り出して印刷する例を示します。呼び出されたオブジェクトに関する詳細を取得するには、おそらくスタックフレームを参照する必要があります。

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <jvmti.h> 

static jvmtiEnv *jvmti = NULL; 
static jvmtiCapabilities capa; 

static jint check_jvmti_error(jvmtiEnv *jvmti, 
           jvmtiError errnum, 
           const char *str) { 

    if (errnum != JVMTI_ERROR_NONE) { 
     char *errnum_str; 
     errnum_str = NULL; 
     (void) (*jvmti)->GetErrorName(jvmti, errnum, &errnum_str); 
     printf("ERROR: JVMTI: %d(%s): %s\n", 
       errnum, 
       (errnum_str == NULL ? "Unknown" : errnum_str), 
       (str == NULL ? "" : str)); 
     return JNI_ERR; 
    } 
    return JNI_OK; 
} 

void JNICALL callbackMethodEntry(jvmtiEnv *jvmti_env, 
           JNIEnv* jni_env, 
           jthread thread, 
           jmethodID method) { 

    char* method_name; 
    char* method_signature; 
    char* generic_ptr_method; 
    char* generic_ptr_class; 
    char* class_name; 
    jvmtiError error; 
    jclass clazz; 

    error = (*jvmti_env)->GetMethodName(jvmti_env, 
             method, 
             &method_name, 
             &method_signature, 
             &generic_ptr_method); 
    if (check_jvmti_error(jvmti_env, error, "Failed to get method name")) { 
     return; 
    } 

    if (strcmp("invoke", method_name) == 0) { 

     error 
       = (*jvmti_env)->GetMethodDeclaringClass(jvmti_env, method, 
         &clazz); 
     if (check_jvmti_error(jvmti_env, error, 
       "Failed to get class for method")) { 
      (*jvmti_env)->Deallocate(jvmti_env, method_name); 
      (*jvmti_env)->Deallocate(jvmti_env, method_signature); 
      (*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method); 
      return; 
     } 

     error = (*jvmti_env)->GetClassSignature(jvmti_env, clazz, &class_name, 
       &generic_ptr_class); 
     if (check_jvmti_error(jvmti_env, error, "Failed to get class signature")) { 
      (*jvmti_env)->Deallocate(jvmti_env, method_name); 
      (*jvmti_env)->Deallocate(jvmti_env, method_signature); 
      (*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method); 
      return; 
     } 

     if (strcmp("Ljava/lang/reflect/Method;", class_name) == 0) { 
      printf("Method entered: %s.%s.%s\n", class_name, method_name, 
        method_signature); 
     } 
     (*jvmti_env)->Deallocate(jvmti_env, class_name); 
     (*jvmti_env)->Deallocate(jvmti_env, generic_ptr_class); 
    } 

    (*jvmti_env)->Deallocate(jvmti_env, method_name); 
    (*jvmti_env)->Deallocate(jvmti_env, method_signature); 
    (*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method); 
} 

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 

    jint result; 
    jvmtiError error; 
    jvmtiEventCallbacks callbacks; 

    result = (*jvm)->GetEnv(jvm, (void**) &jvmti, JVMTI_VERSION_1_0); 
    if (result != JNI_OK || jvmti == NULL) { 
     printf("error\n"); 
     return JNI_ERR; 
    } else { 
     printf("loaded agent\n"); 
    } 

    (void) memset(&capa, 0, sizeof(jvmtiCapabilities)); 
    capa.can_generate_method_entry_events = 1; 

    error = (*jvmti)->AddCapabilities(jvmti, &capa); 
    if (check_jvmti_error(jvmti, error, "Unable to set capabilities") != JNI_OK) { 
     return JNI_ERR; 
    } 

    (void) memset(&callbacks, 0, sizeof(callbacks)); 
    callbacks.MethodEntry = &callbackMethodEntry; 
    error = (*jvmti)->SetEventCallbacks(jvmti, 
             &callbacks, 
             (jint) sizeof(callbacks)); 
    if (check_jvmti_error(jvmti, error, "Unable to set callbacks") != JNI_OK) { 
     return JNI_ERR; 
    } 

    error = (*jvmti)->SetEventNotificationMode(jvmti, 
               JVMTI_ENABLE, 
               JVMTI_EVENT_METHOD_ENTRY, 
               (jthread) NULL); 
    if (check_jvmti_error(jvmti, error, 
      "Unable to set method entry notifications") != JNI_OK) { 
     return JNI_ERR; 
    } 

    return JNI_OK; 
} 
関連する問題