Byteman 使用指南(五)

FunTester發表於2025-02-10

規則繫結

事件規範中包含一個繫結規範,用於在規則觸發時計算並引用變數的值。這些繫結值會在每次規則觸發時重新計算,並在測試規則條件之前使用。例如:

# 繫結示例
RULE countdown at commit
CLASS com.arjuna.wst11.messaging.engines.CoordinatorEngine
METHOD commit
AT READ state
BIND engine:CoordinatorEngine = $0;
     recovered:boolean = engine.isRecovered();
     identifier:String = engine.getId()
. . .
ENDRULE

在此示例中,變數 engine 繫結到觸發規則的 commit 方法呼叫的接收者,該接收者透過 $0 引數引用。如果 commit 是靜態方法,則引用 $0 會導致型別檢查異常。方法的引數可以透過 $1, $2 等索引訪問。宣告 engine 時可以指定型別為 CoordinatorEngine,但這不是必須的,因為型別可以從 $0 的型別推斷。

類似地,變數 recoveredidentifier 透過右側表示式計算值。型別說明符是可選的,未指定時系統會自動推斷其型別。對於不需要繫結變數的規則,可以使用特殊語法 BIND NOTHING,或直接省略 BIND 子句。

向下轉型的規則繫結

繫結初始化不僅用於為計算的值引入變數,還可以執行向下轉型(downcast),將通用型別值分配給更具體的子類型別的規則變數。例如:

# 向下轉型示例
RULE countdown at commit
CLASS com.arjuna.wst11.messaging.engines.CoordinatorEngine
METHOD commit
AT READ state
BIND engine:CoordinatorEngine = $0;
     endpoint:javax.xml.ws.EndpointReference = engine.participant;
     w3cEndpoint:javax.xml.ws.wsaddressing.W3CEndpointReference = endpoint
. . .
ENDRULE

在此規則中,engine.participant 的值被繫結到變數 endpoint,其型別為 EndpointReference。隨後,變數 w3cEndpoint 使用 endpoint 的值,並透過向下轉型宣告為 W3CEndpointReference 型別。這在其他規則賦值中可能導致型別錯誤,但在繫結初始化中是允許的,前提是轉換合法。

位元組碼檢查器在初始化時會驗證型別轉換是否有效,並在失敗時丟擲異常。例如,假設 CoordinatorEngine 的欄位 participant 被宣告為 W3CEndpointReference 型別,則上述繫結永遠不會失敗。

向下轉型在需要處理通用型別(如 List)時特別有用。由於泛型型別資訊在編譯時會被擦除,位元組碼檢查器無法直接識別其具體型別。例如,透過列表檢索的值總是被視為 Object 型別。如果已知列表儲存的是特定型別的值,可以透過 BIND 子句將其向下轉型為具體型別。

規則表示式

事件繫結中等號右側的表示式可以是 Byteman 支援的任何 Java 表示式,包括:

  • 繫結變數的引用。
  • 觸發方法的接收者或引數的引用。
  • 觸發點範圍內區域性變數的引用。
  • 特殊變數 $!$^$#$*$@$CLASS$METHOD 的引用。
  • 靜態欄位或例項欄位的引用。
  • 原始字面量或陣列字面量。
  • 方法呼叫(靜態或例項)。
  • 內建操作呼叫。

表示式還可以由複雜組合構成,支援 Java 運算子,如 +, -, *, /, %, &&, ||, ==, !=, <, <= 等。三元運算子 ? : 也被支援。

特殊變數

  • $!:繫結觸發點處的返回值,在 AT EXITAFTER INVOKE 規則中有效。
  • $^:繫結觸發點處丟擲的異常,在 AT THROWAT EXCEPTION EXIT 規則中有效。
  • $#:繫結為觸發方法的引數數量。
  • $*:繫結為包含觸發方法接收者和引數的 Object[] 陣列。
  • $@:在 AT INVOKE 規則中有效,繫結為目標方法的接收者及呼叫引數陣列。
  • $CLASS:繫結為觸發規則的類的完全限定名。
  • $METHOD:繫結為觸發規則的方法的完整簽名。
  • $NEWCLASS:在 AT NEWAFTER NEW 規則中有效,繫結為新操作建立的類名。

規則條件

規則條件是布林型別的表示式,用於決定規則是否觸發。例如:

RULE countdown at commit
CLASS com.arjuna.wst11.messaging.engines.CoordinatorEngine
METHOD commit
AT READ state
BIND engine:CoordinatorEngine = $this;
     recovered:boolean = engine.isRecovered();
IF recovered
. . .
ENDRULE

上述條件測試繫結變數 recovered 的值是否為 true。以下示例使用方法呼叫直接作為條件:

IF engine.isRecovered()

如果相關欄位直接儲存布林值,則條件可以簡化為:

IF engine.recovered

對於始終觸發的規則,可以使用布林字面量 true 作為條件。

規則動作

規則動作可以是返回值、丟擲異常、或分號分隔的表示式序列。支援的主要型別包括:

  1. 返回動作(return

    關鍵字 return 用於提前結束觸發方法。如果方法非 void,需提供返回值。例如:

    DO return false
    
  2. 丟擲動作(throw

    關鍵字 throw 可丟擲執行時異常或觸發方法宣告的受檢異常。例如:

    DO throw new RuntimeException("Error occurred")
    
  3. 空動作(NOTHING

    表示無具體動作。

內建呼叫

內建呼叫是由 Byteman 提供的工具方法,例如:

  • debug(String):列印除錯資訊。
  • killJVM():立即終止 JVM,模擬崩潰。

內建呼叫作為規則條件或動作的一部分執行,例如:

DO debug("killing JVM"), killJVM()

Byteman 允許透過擴充套件 Helper 類新增自定義內建呼叫,為規則提供更多功能。

FunTester 原創精華

【連載】從 Java 開始效能測試

  • 混沌工程、故障測試、Web 前端
  • 服務端功能測試
  • 效能測試專題
  • Java、Groovy、Go
  • 白盒、工具、爬蟲、UI 自動化
  • 理論、感悟、影片
如果覺得我的文章對您有用,請隨意打賞。您的支援將鼓勵我繼續創作!
打賞支援
暫無回覆。