2017-07-26 648 views
1

我正在使用JVMTI編寫應用程序。我正在嘗試使用字節碼:通過在每個方法條目上注入方法調用。解決JNI中的依賴關係DefineClass

我知道該怎麼做,但問題出在儀器類上,比如說它叫做Proxy,我用JNI函數DefineClass加載。我的Proxy在Java類庫中有一些依賴關係,目前只有java.lang.ThreadLocal<Boolean>

現在,說我有這個,其中inInstrumentMethod是一個普通的boolean

public static void onEntry(int methodID) 
{ 
    if (inInstrumentMethod) { 
     return; 
    } else { 
     inInstrumentMethod = true; 
    } 

    System.out.println("Method ID: " + methodID); 

    inInstrumentMethod = false; 
} 

代碼編譯和作品。但是,如果我使inInstrumentMethod a java.lang.ThreadLocal<Boolean>,我得到一個NoClassDefFoundError。代碼:

private static ThreadLocal<Boolean> inInstrumentMethod = new ThreadLocal<Boolean>() { 
     @Override protected Boolean initialValue() { 
      return Boolean.FALSE; 
     } 
    }; 

public static void onEntry(int methodID) 
{ 
    if (inInstrumentMethod.get()) { 
     return; 
    } else { 
     inInstrumentMethod.set(true); 
    } 

    System.out.println("Method ID: " + methodID); 

    inInstrumentMethod.set(false); 
} 

我的猜測是,依賴沒有被正確解析,並java.lang.ThreadLocal未加載(因而無法找到)。那麼問題是,如何強制Java加載java.lang.ThreadLocal?在這種情況下,我認爲我不能使用DefineClass;有沒有其他選擇?

+0

你得到'NoClassDefFoundError'爲什麼類? – EJP

回答

1

我不認爲有解決標準類java.lang.ThreadLocal的問題,而是與內部類擴展它,通過

new ThreadLocal<Boolean>() { 
    @Override protected Boolean initialValue() { 
     return Boolean.FALSE; 
    } 
}; 

通過DefineClass解決這個產生的的確可能因循環是不可能的內部類和外部類之間的依賴關係,所以沒有允許定義它們的順序,除非你有一個完整的ClassLoader,它可以按需返回類。

最簡單的辦法是避免內部類在所有的產生,這是可能的與Java 8:

private static ThreadLocal<Boolean> inInstrumentMethod 
            = ThreadLocal.withInitial(() -> Boolean.FALSE); 

如果使用之前的Java 8版本,你不能用它那方式,所以在這種情況下,最好的解決辦法,就是重寫代碼接受null默認值作爲初始值,無需指定不同的初始值:

private static ThreadLocal<Boolean> inInstrumentMethod = new ThreadLocal<>(); 

public static void onEntry(int methodID) 
{ 
    if (inInstrumentMethod.get()!=null) { 
     return; 
    } else { 
     inInstrumentMethod.set(true); 
    } 

    System.out.println("Method ID: " + methodID); 

    inInstrumentMethod.set(null); 
} 

你也可以轉換的是匿名內部班級到頂級班。從那以後,這個類對先前的外部類沒有依賴性,在定義使用它的類之前首先定義該子類ThreadLocal應該解決問題。

+0

謝謝。你完全正確!我讓內部類成爲適當的類,它工作得很好。 – xuq01