2016-03-22 39 views
2

我正在使用tomcat7實例來運行Java應用程序。我的應用程序需要暴露的Java工具。這是通過一個javaagent完成的,我在啓動時將代理傳遞給setenv.bat腳本中的JVM。無法爲tomcat公開Java Instrumentation jvm

set JAVA_OPTS=%JAVA_OPTS% -javaagent:"C:\path\to\agent.jar" 

在清單文件I具有所需的部分:

Premain-Class: package.name.agent.ExposeInstrumentation 

在代理類的的premain方法通過一個靜態方法分配由JVM提供給一個靜態變量訪問儀表

public final class ExposeInstrumentation { 
private static Instrumentation s_instrumentation; 
public static void premain(String arguments, Instrumentation instrumentation) { 
    s_instrumentation = instrumentation; 
} 

public static Instrumentation getInstrumentation() { 
    return s_instrumentation; 
} 
} 

但在我的代碼時,我這樣做:

Instrumentation instrumentation = ExposeInstrumentation.getInstrumentation(); 

getInstrumentation()返回null;

什麼問題?

UPDATE

我做了一些進一步的調試和倍美力會被執行並且s_instrumentation接收儀器,但是當我在我的代碼s_instumentation後來打電話getInstrumentation設置爲null。這是奇怪的,我認爲價值仍然是有效的思考方案的生命。

+0

實際上是否調用了'premain'方法? – Berger

+0

premain被執行,但我沒有得到任何儀器 – dragosb

回答

1

我假設你正在加載類ExposeInstrumentation兩次。一旦通過應用程序類加載器(它是child-first (reverse-order)),並且一次通過Java代理(其中該類由系統類加載器自動加載)。因此,ExposeInstrumentation類會在您訪問應用程序中未設置字段的地方加載兩次。

您可以通過訪問明確由系統類加載器加載的類解決這個問題:

class ExposeInstrumentation { 

    // public to assure accessability 
    public static Instrumentation s_instrumentation; 

    public static void premain(String arguments, Instrumentation inst) { 
    s_instrumentation = inst; 
    } 

    public static Instrumentation getInstrumentation() { 
    try { 
     return (Instrumentation) ClassLoader.getSystemClassLoader() 
      .loadClass(ExposeInstrumentation.class.getName()) 
      .getDeclaredField("s_instrumentation") 
      .get(null); 
    } catch(Exception e) { 
     return null; 
    } 
    } 
} 

您還可以檢查出,提供了一個代理的這個功能多(運行時安裝)Byte Buddy Agent project。通過Byte Buddy,您可以簡單地致電ByteBuddyAgent.getInstrumentation()

+0

也...有沒有辦法阻止應用程序ClassLoader加載ExposeInstrumentation,因此它不會被加載兩次? – dragosb

+0

應該是'loadClass'而不是'findClass'。您可以通過將ExposeInstrumentation類放入其自己的模塊中,併爲Web應用程序聲明*提供的*範圍依賴項來防止重複加載。只要代理人連接,這將起作用。 –