我正在编写一个游戏引擎/库,其中我有一个事件调度器类,它通过调用"注册"事件处理程序类的侦听器方法来调度事件。可以通过调用适当的调度程序方法向事件调度程序注册事件处理程序/侦听器。
这显然会导致一些用于注册每个事件处理程序的样板代码(并且我的引擎的其他方面也有类似的玻利尔板代码),所以我想知道 - 如何使用 Instrumentation 在加载事件处理程序类期间添加所有必要的代码,以便在编码时无需向事件调度程序显式注册 - 当程序跑。
我的理解是,为了使用检测,应该使用一些字节码修饰符API。我知道两个 - ASM 和 BCEL。我应该使用哪一个?显然,这是我正在尝试执行的一项简单任务,因此我想要一个更容易学习且记录更好的任务。
编辑:这是一个具体的例子。
原始事件处理程序类:
@Handler //indicates this this class should be transformed
public class MouseEventHandler implements EventHandler<MouseEvent>
{
//hidden default constructor
public void handleEvent(MouseEvent event)
{ ... }
}
改造后:
@Handler
public class MouseEventHandler implements EventHandler<MouseEvent>
{
public MouseEventHandler()
{
//add this line of code to default constructor
Game.getEventDispatcher().addEventHandler(this);
}
public void handleEvent(MouseEvent event)
{ ... }
}
Java 字节码库:
- ASM发展迅速且积极。
- BCEL相对较慢。
- 如果你不熟悉Java字节码,Javassist可能是最容易上手的。
- cglib 建立在 ASM 之上,提供了一些更高级别的抽象。
- Byte Buddy通过DSL生成类。积极维护并看到使用量不断增加。
但是,在进入字节码操作之前,我会考虑其他选择。
将逻辑添加到几个类中可能很无聊,但除非你有成千上万的处理程序,否则这就是我会走的路。保持简单。
可是
Game.registerHandler( this );
将更加面向对象。
在每个类中添加逻辑的替代方法是引入一个负责实例化处理程序的工厂。
HandlerFactory.createMouseHandler();
方法createMouseHandler
包含类似的东西
Handler mh = new MousheHandler();
registerHandler(mh);
return mh;
如果你不想要这些选项中的任何一个,我会考虑一个方面框架(可能是AspectJ)或一个控制反转的容器(也许是Spring IoC)。方面允许您注释源代码,并在所选位置"编织"代码。IoC 容器允许您控制对象的生命周期(例如实例化)。两者都在后台使用字节码检测。
但是如果你想自己做仪器,我只能比较我个人使用的Javsist和ASM。
ASM是低级的,实际上是在java字节码级别运行的。你必须熟悉它。该框架设计得很好,手册很棒,它是一个很棒的库。一方面,替换字节码模式可能很复杂,因为它需要所谓的"有状态"转换。另一方面,您可以完全控制字节码。
贾瓦斯更高级。您不会在字节码的原始级别进行操作,而是稍微高一点的级别,例如字段读/写、消息发送、构造函数。此外,它还允许您使用常规 java 语法指定更改,然后由框架编译。API 有点混乱,因为该项目多年来一直在增长。有关于框架的文档,但不像 ASM 那样集中。