事件规范中包含一个绑定规范,用于在规则触发时计算并引用变量的值。这些绑定值会在每次规则触发时重新计算,并在测试规则条件之前使用。例如:
# 绑定示例
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 的类型推断。
类似地,变量 recovered 和 identifier 通过右侧表达式计算值。类型说明符是可选的,未指定时系统会自动推断其类型。对于不需要绑定变量的规则,可以使用特殊语法 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 EXIT 和 AFTER INVOKE 规则中有效。$^:绑定触发点处抛出的异常,在 AT THROW 和 AT EXCEPTION EXIT 规则中有效。$#:绑定为触发方法的参数数量。$*:绑定为包含触发方法接收者和参数的 Object[] 数组。$@:在 AT INVOKE 规则中有效,绑定为目标方法的接收者及调用参数数组。$CLASS:绑定为触发规则的类的完全限定名。$METHOD:绑定为触发规则的方法的完整签名。$NEWCLASS:在 AT NEW 和 AFTER 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 作为条件。
规则动作可以是返回值、抛出异常、或分号分隔的表达式序列。支持的主要类型包括:
返回动作(return)
关键字 return 用于提前结束触发方法。如果方法非 void,需提供返回值。例如:
DO return false
抛出动作(throw)
关键字 throw 可抛出运行时异常或触发方法声明的受检异常。例如:
DO throw new RuntimeException("Error occurred")
空动作(NOTHING)
表示无具体动作。
内置调用是由 Byteman 提供的工具方法,例如:
debug(String):打印调试信息。killJVM():立即终止 JVM,模拟崩溃。内置调用作为规则条件或动作的一部分执行,例如:
DO debug("killing JVM"), killJVM()
Byteman 允许通过扩展 Helper 类添加自定义内置调用,为规则提供更多功能。
FunTester 原创精华