JavaTM 2 Platform
Standard Ed. 6

java.lang.instrument
介面 Instrumentation


public interface Instrumentation

此類別提供檢測 Java 程式語言程式碼所需的服務。檢測是向方法中添加位元組碼,以搜集各種工具所使用的資料。由於更改完全是進行添加,所以這些工具不修改應用程序的狀態或行為。這種無害工具的例子包括鏡像代理、分析器、覆寫分析器和事件記錄器。

獲取 Instrumentation 介面的實例有兩種方式:

  1. 當 JVM 以指示一個代理類別的方式啟動時,將傳遞給代理類別的 premain 方法一個 Instrumentation 實例。

  2. 當 JVM 提供某種機制在 JVM 啟動之後某一時刻啟動代理時,將傳遞給代理程式碼的 agentmain 方法一個 Instrumentation 實例。

這些機制在套件規範中描述。

如果某個代理獲得了 Instrumentation 實例,它便可以在任何時候調用該實例上的方法。

從以下版本開始:
1.5

方法摘要
 void addTransformer(ClassFileTransformer transformer)
          註冊提供的轉換器。
 void addTransformer(ClassFileTransformer transformer, boolean canRetransform)
          註冊提供的轉換器。
 void appendToBootstrapClassLoaderSearch(JarFile jarfile)
          指定 JAR 檔案,檢測類別由引導類別載入器定義。
 void appendToSystemClassLoaderSearch(JarFile jarfile)
          指定 JAR 檔案,檢測類別由系統類別載入器定義。
 Class[] getAllLoadedClasses()
          返回 JVM 當前載入的全部類別的陣列。
 Class[] getInitiatedClasses(ClassLoader loader)
          返回所有初始化載入器是 loader 的類別的陣列。
 long getObjectSize(Object objectToSize)
          返回指定物件使用的特定於實作的近似存儲量。
 boolean isModifiableClass(Class<?> theClass)
          確定一個類別是否可以被 retransformationredefinition 修改。
 boolean isNativeMethodPrefixSupported()
          返回當前 JVM 配置是否支持設置本機方法前綴
 boolean isRedefineClassesSupported()
          返回當前 JVM 配置是否支持類別的重定義。
 boolean isRetransformClassesSupported()
          返回當前 JVM 配置是否支持類別的重轉換。
 void redefineClasses(ClassDefinition... definitions)
          使用提供的類別檔案重定義提供的類別集。
 boolean removeTransformer(ClassFileTransformer transformer)
          註銷提供的轉換器。
 void retransformClasses(Class<?>... classes)
          重轉換提供的類別集。
 void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix)
          通過允許重試,將前綴應用到名稱,此方法修改本機方法解析的失敗處理。
 

方法詳細資訊

addTransformer

void addTransformer(ClassFileTransformer transformer,
                    boolean canRetransform)
註冊提供的轉換器。所有以後的類別定義對於該轉換器都是可見的,任何已註冊轉換器所依賴的類別定義除外。 載入類別、重定義類別時將調用該轉換器。如果 canRetransform 為 true,那麼重轉換類別時也將調用該轉換器。 有關轉換調用的順序,請參見 ClassFileTransformer.transform。 如果轉換器在執行過程中拋出異常,JVM 將仍然按順序調用其他已註冊轉換器。可以多次添加相同的轉換器,但建議最好創建一個新的轉換器類別實例來避免這樣做。

此方法旨在用於檢測,正如類別規範所述。

參數:
transformer - 要註冊的轉換器
canRetransform - 此轉換器的轉換是否可以重轉換
拋出:
NullPointerException - 如果傳遞了 null 轉換器
UnsupportedOperationException - 如果 canRetransform 為 true 但當前 JVM 的配置不允許重轉換(isRetransformClassesSupported() 為 false)。
從以下版本開始:
1.6

addTransformer

void addTransformer(ClassFileTransformer transformer)
註冊提供的轉換器。

addTransformer(transformer, false) 相同。

參數:
transformer - 要註冊的轉換器
拋出:
NullPointerException - 如果傳遞了一個 null 轉換器
另請參見:
addTransformer(ClassFileTransformer,boolean)

removeTransformer

boolean removeTransformer(ClassFileTransformer transformer)
註銷提供的轉換器。以後的類別定義將不再向該轉換器顯示。移除最新添加的轉換器的比對實例。由於類別載入的多執行緒特性,在調用被移除後,轉換器還可能接收調用。所以編寫轉換器時應防止出現這種情況。

參數:
transformer - 要註銷的轉換器
返回:
如果找到並移除轉換器,則返回 true;如果找不到轉換器,則返回 false
拋出:
NullPointerException - 如果傳遞了一個 null 轉換器

isRetransformClassesSupported

boolean isRetransformClassesSupported()
返回當前 JVM 配置是否支持類別的重轉換。 轉換已載入類別是 JVM 的一個可選性能。 僅當 Can-Retransform-Classes 清單屬性在代理 JAR 檔案中設置為 true(如套件規範所述),且 JVM 支持此性能時,才支持重轉換。 在單個 JVM 的單個實例化過程中,多次調用此方法將總是返回相同的答案。

返回:
如果當前 JVM 配置支持類別的重轉換,則返回 true;如果不支持,則返回 false。
從以下版本開始:
1.6
另請參見:
retransformClasses(java.lang.Class...)

retransformClasses

void retransformClasses(Class<?>... classes)
                        throws UnmodifiableClassException
重轉換提供的類別集。

此函數為檢測已載入類別提供了方便。 當最初載入了類別或重定義了類別時,初始類別檔案位元組可以使用 ClassFileTransformer 轉換。 此函數返回轉換進程(以前是否發生過轉換)。 此轉換按以下步驟進行:

轉換的順序在 transform 方法中描述。在自動重新應用不可重轉換的轉換時,也將使用這一順序。

最初的類別檔案位元組表示(應用轉換前)傳遞給 ClassLoader.defineClassredefineClasses 的位元組,但有可能不完全比對。常數池的佈局或內容可能不同。常數池的條目可能多一些或少一些。常數池條目的順序可能不同,但是,方法位元組碼中常數池的索引將是對應的。一些屬性可能不存在。在順序沒有意義的地方(例如,方法的順序),可能不保留順序。

此方法在一個集合上操作,以便允許同時對多個類別進行相互依賴的更改(重轉換類別 A 要求重轉換類別 B)。

如果重轉換的方法有活動的堆疊(stack)訊框,那麼這些活動的幀將繼續運行原方法的位元組碼。重轉換的方法將用於新的調用。

此方法不會引起任何初始化操作,JVM 慣例語義下發生的初始化除外。換句話說,重定義一個類別不會引起其初始化方法的運行。靜態變數的值將與調用之前的值一樣。

重轉換類別的實例不受影響。

重轉換可能會更改方法體、常數池和屬性。重轉換不得添加、移除、重命名欄位或方法;不得更改方法簽章、繼承關係。在以後的版本中,可能會取消這些限制。在應用轉換之前,類別檔案位元組不會被檢查、驗證和安裝。如果結果位元組錯誤,此方法將拋出異常。

如果此方法拋出異常,則不會重轉換任何類別。

此方法旨在用於檢測,正如類別規範所述。

參數:
classes - 要轉換的類別陣列; 允許長度為 0 陣列,在這種情況下,此方法不執行任何操作
拋出:
UnmodifiableClassException - 如果不能修改指定的類別(isModifiableClass(java.lang.Class) 返回 false
UnsupportedOperationException - 如果 JVM 的當前配置不允許重轉換(isRetransformClassesSupported() 為 false),或者重轉換試圖做出不受支持的更改
ClassFormatError - 如果資料不包含有效的類別
NoClassDefFoundError - 如果類別檔案中的名稱不等於類別的名稱
UnsupportedClassVersionError - 如果類別檔案版本號不受支持
ClassCircularityError - 如果新類別包含循環
LinkageError - 如果發生連接錯誤
NullPointerException - 如果提供的類別陣列或其任意元件為 null
從以下版本開始:
1.6
另請參見:
isRetransformClassesSupported(), addTransformer(java.lang.instrument.ClassFileTransformer, boolean), ClassFileTransformer

isRedefineClassesSupported

boolean isRedefineClassesSupported()
返回當前 JVM 配置是否支持類別的重定義。重定義已載入類別是 JVM 的一個可選性能。 僅當 Can-Retransform-Classes 清單屬性在代理 JAR 檔案中設置為 true(如套件規範所述),且 JVM 支持此性能時,才支持重轉換。 在執行單個 JVM 的單實例化過程中,對此方法的多次調用將始終返回同一應答。

返回:
如果當前 JVM 配置支持類別的重定義,則為 true,否則為 false。
另請參見:
redefineClasses(java.lang.instrument.ClassDefinition...)

redefineClasses

void redefineClasses(ClassDefinition... definitions)
                     throws ClassNotFoundException,
                            UnmodifiableClassException
使用提供的類別檔案重定義提供的類別集。

此方法用於替代類別的定義,而不參考現有的類別檔案位元組,這與 fix-and-continue 除錯過程中重新編譯源程式碼時所做的一樣。需要轉換現有類別檔案位元組的地方(例如,位元組碼檢測中)應該使用 retransformClasses

此方法在一個集合上操作,以便允許同時對多個類別進行相互依賴的更改(重定義類別 A 要求重定義類別 B)。

如果重定義的方法有活動的堆疊(stack)訊框,那麼這些活動的幀將繼續運行原方法的位元組碼。將在新的調用上使用此重定義的方法。

此方法不會引起任何初始化操作,JVM 慣例語義下發生的初始化除外。換句話說,重定義一個類別不會引起其初始化方法的運行。靜態變數的值將與調用之前的值一樣。

重定義類別的實例不受影響。

重定義可能會更改方法體、常數池和屬性。重定義不得添加、移除、重命名欄位或方法;不得更改方法簽章、繼承關係。在以後的版本中,可能會取消這些限制。在應用轉換之前,類別檔案位元組不會被檢查、驗證和安裝。如果結果位元組錯誤,此方法將拋出異常。

如果此方法拋出異常,則不會重定義任何類別。

此方法旨在用於檢測,正如類別規範所述。

參數:
definitions - 要使用相應定義來進行重定義的類別陣列;允許長度為 0 陣列,在這種情況下,此方法不執行任何操作
拋出:
UnmodifiableClassException - 如果無法修改指定的類別(isModifiableClass(java.lang.Class) 返回 false
UnsupportedOperationException - 如果 JVM 的當前配置不允許重定義(isRedefineClassesSupported() 為 false)或重定義試圖做出不受支持的更改
ClassFormatError - 如果資料不包含有效類別
NoClassDefFoundError - 如果類別檔案中的名稱與類別名稱不相等
UnsupportedClassVersionError - 如果類別檔案版本號不受支持
ClassCircularityError - 如果新類別包含循環
LinkageError - 如果發生連接錯誤
NullPointerException - 如果提供的定義陣列或其任何元件為 null
ClassNotFoundException - 不會拋出(存在只是為了相容)
另請參見:
isRedefineClassesSupported(), addTransformer(java.lang.instrument.ClassFileTransformer, boolean), ClassFileTransformer

isModifiableClass

boolean isModifiableClass(Class<?> theClass)
確定一個類別是否可以被 retransformationredefinition 修改。 如果類別可以被修改,那麼此方法返回 true。 如果類別不能被修改,那麼此方法返回 false

對於要重轉換的類別,isRetransformClassesSupported() 也必須為 true。但 isRetransformClassesSupported() 的值不影響此函數返回的值。 對於要重定義的類別,isRedefineClassesSupported() 也必須為 true。但 isRedefineClassesSupported() 的值不影響此函數返回的值。

基本類別(例如 java.lang.Integer.TYPE)和陣列類別不可修改。

拋出:
NullPointerException - 如果指定的類別為 null
從以下版本開始:
1.6
另請參見:
retransformClasses(java.lang.Class...), isRetransformClassesSupported(), redefineClasses(java.lang.instrument.ClassDefinition...), isRedefineClassesSupported()

getAllLoadedClasses

Class[] getAllLoadedClasses()
返回 JVM 當前載入的全部類別的陣列。

返回:
包含 JVM 載入的全部類別的陣列;如果沒有,則返回長度為 0 陣列

getInitiatedClasses

Class[] getInitiatedClasses(ClassLoader loader)
返回所有初始化載入器是 loader 的類別的陣列。如果提供的載入器為 null,則返回由引導類別載入器初始化的類別。

參數:
loader - 將返回其初始化類別列表的載入器
返回:
包含初始化載入器是 loader 的類別的陣列;如果沒有,則返回長度為 0 陣列

getObjectSize

long getObjectSize(Object objectToSize)
返回指定物件使用的特定於實作的近似存儲量。該結果可能包括物件的部分或全部開銷,因此,在一個實作中進行比較時較為有用,但不能用於實作之間的比較。 該估計值在 JVM 的單個調用期間可能發生變化。

參數:
objectToSize - 需要確定大小的物件
返回:
指定物件使用的特定於實作的近似存儲量
拋出:
NullPointerException - 如果提供的 Object 為 null

appendToBootstrapClassLoaderSearch

void appendToBootstrapClassLoaderSearch(JarFile jarfile)
指定 JAR 檔案,檢測類別由引導類別載入器定義。

當虛擬機器的內置類別載入器(稱為「引導類別載入器」)未能成功搜尋到類別時,JAR 檔案中的條目也將被搜尋。

可以多次使用此方法,按照調用此方法的順序添加多個要搜尋的 JAR 檔案。

除了需要引導類別載入器為檢測而定義的類別或資源外,代理應該注意確保 JAR 不包含任何其他類別或資源。 違反此規定將導致難以診斷的不可預料行為。例如,假設有載入器 L,L 的代理父載入器為引導類別載入器。 此外,有一個類別 C 的方法,有一個 L 定義的類別,參考了非公共存取類別 C$1。如果 JAR 檔案包含類別 C$1,那麼引導類別載入器的代理將導致 C$1 被引導類別載入器定義。此例中將拋出 IllegalAccessError,這可能導致應用程序失敗。一個避免這類別問題的辦法是,對檢測類別使用唯一的套件名稱。

Java 虛擬機器規範規定,後續嘗試解析 Java 虛擬機器以前未能成功解析的符號參考將總是失敗,並拋出與最初解析嘗試失敗時相同的錯誤。因此,如果 JAR 檔案包含的某個條目對應於 Java 虛擬機器未能成功解析參考的類別,那麼後續嘗試解析該參考將總是失敗,並拋出與最初解析嘗試失敗時相同的錯誤。

參數:
jarfile - 當引導類別載入器未成功搜尋到類別時要搜尋的 JAR 檔案。
拋出:
NullPointerException - 如果 jarfilenull
從以下版本開始:
1.6
另請參見:
appendToSystemClassLoaderSearch(java.util.jar.JarFile), ClassLoader, JarFile

appendToSystemClassLoaderSearch

void appendToSystemClassLoaderSearch(JarFile jarfile)
指定 JAR 檔案,檢測類別由系統類別載入器定義。 當代理的系統類別載入器(參見 getSystemClassLoader())未能成功搜尋到類別時,JarFile 中的條目也將被搜尋。

可以多次使用此方法,按照調用此方法的順序添加多個要搜尋的 JAR 檔案。

除了需要系統類別載入器為檢測而定義的類別或資源外,代理應該注意確保 JAR 不包含任何其他類別或資源。 違反此規定將導致難以診斷的不可預料行為。(參見 appendToBootstrapClassLoaderSearch)。

如果實作了名為 appendToClassPathForInstrumentation 的方法(帶有一個型別為 java.lang.String 的參數),那麼系統類別載入器支持添加要搜尋的 JAR 檔案。不要求該方法具有 public 存取權。JAR 檔案名可以通過對 jarfile 調用 getName() 方法獲取,並將作為參數提供給 appendtoClassPathForInstrumentation 方法。

Java 虛擬機器規範規定,後續嘗試解析 Java 虛擬機器以前未能成功解析的符號參考將總是失敗,並拋出與最初解析嘗試失敗時相同的錯誤。因此,如果 JAR 檔案包含的某個條目對應於 Java 虛擬機器未能成功解析參考的類別,那麼後續嘗試解析該參考將總是失敗,並拋出與最初解析嘗試失敗時相同的錯誤。

此方法不更改 java.class.path 系統屬性的值。

參數:
jarfile - 當系統類別載入器未成功搜尋到類別時要搜尋的 JAR 檔案。
拋出:
UnsupportedOperationException - 如果系統類別載入器不支持添加要搜尋的 JAR 檔案。
NullPointerException - 如果 jarfilenull
從以下版本開始:
1.6
另請參見:
appendToBootstrapClassLoaderSearch(java.util.jar.JarFile), ClassLoader.getSystemClassLoader(), JarFile

isNativeMethodPrefixSupported

boolean isNativeMethodPrefixSupported()
返回當前 JVM 配置是否支持設置本機方法前綴。 設置本機方法前綴是 JVM 的一個可選性能。 僅當 Can-Set-Native-Method-Prefix 清單屬性在代理 JAR 檔案中設置為 true(如套件規範所述),且 JVM 支持此性能時,才支持設置本機方法前綴。 在單個 JVM 的單個實例化過程中,多次調用此方法將總是返回相同的應答。

返回:
如果當前 JVM 配置支持設置本機方法前綴,則返回 true;否則返回 false。
從以下版本開始:
1.6
另請參見:
setNativeMethodPrefix(java.lang.instrument.ClassFileTransformer, java.lang.String)

setNativeMethodPrefix

void setNativeMethodPrefix(ClassFileTransformer transformer,
                           String prefix)
通過允許重試,將前綴應用到名稱,此方法修改本機方法解析的失敗處理。 當與 ClassFileTransformer 一起使用時,它允許檢測本機方法。

由於本機方法不能直接檢測(它們沒有位元組碼),因此必須使用可以檢測的非本機方法包裹它們。例如,如果有:

   native boolean foo(int x);

那麼可以轉換類別檔案(在類別的初始定義過程中使用 ClassFileTransformer),使之變成:

   boolean foo(int x) {
     ... record entry to foo ...
     return wrapped_foo(x);
   }
   
   native boolean wrapped_foo(int x);

其中 foo 變為實際本機方法的套件裝器,並帶有附加前綴 "wrapped_"。注意,將 "wrapped_" 作為前綴並不合適,因為它很有可能與現有方法重名,因此 "$$$MyAgentWrapped$$$_" 之類別更加合適,但那將減少這些範例的可讀性。

外覆器將允許在本機方法調用上收集資料,但現在的問題在於如何連接包裹的方法與本機實作。 也就是說,方法 wrapped_foo 需要被解析為 foo 的本機實作,即:

   Java_somePackage_someClass_foo(JNIEnv* env, jint x)

此函數允許指定前綴並進行恰當的解析。 明確地說,當標準解析失敗時,解析將重新嘗試考慮前綴。進行解析有兩種方式,使用 JNI 函數 RegisterNatives 的顯式解析和常規自動解析。對於 RegisterNatives,JVM 將嘗試以下關聯:

   method(foo) -> nativeImplementation(foo)

若此操作失敗,解析將重試,將指定的前綴添加到方法名,產生校正解析:

   method(wrapped_foo) -> nativeImplementation(foo)

對於自動解析,JVM 將嘗試:

   method(wrapped_foo) -> nativeImplementation(wrapped_foo)

若此操作失敗,解析將重試,從實作名刪除指定的前綴,產生校正解析:

   method(wrapped_foo) -> nativeImplementation(foo)

注意,前綴只在標準解析失敗時使用,因此可以有選擇地包裹本機方法。

每個 ClassFileTransformer 可以執行其本身的位元組程式碼轉換,因此可能要應用多個外覆器層。所以每個轉換器需要其自己的前綴。轉換是按順序應用的,因此前綴(如果應用)也將按相同的順序應用(參見 addTransformer)。 所以,如果三個轉換器應用了外覆器,foo 將變為 $trans3_$trans2_$trans1_foo。但是,如果第二個轉換器沒有對 foo 應用外覆器,那麼它將是 $trans3_$trans1_foo。要有效的確定前綴序列,僅當其非本機外覆器存在時才應用中間前綴。因此,在最後一個範例中,即使 $trans1_foo 不是本機方法,$trans1_ 前綴也將應用,因為 $trans1_foo 存在。

參數:
transformer - 使用此前綴包裹的 ClassFileTransformer。
prefix - 已應用到包裹的本機方法的前綴。
拋出:
NullPointerException - 如果傳入 null 轉換器。
UnsupportedOperationException - 如果 JVM 的當前配置不允許設置本機方法前綴(isNativeMethodPrefixSupported() 為 false)。
IllegalArgumentException - 如果轉換器沒有註冊(參見 addTransformer)。
從以下版本開始:
1.6

JavaTM 2 Platform
Standard Ed. 6

提交錯誤或意見

版權所有 2008 Sun Microsystems, Inc. 保留所有權利。請遵守GNU General Public License, version 2 only