我正在编写一个游戏引擎/库,其中我有一个事件调度程序类,它通过调用“已注册”事件处理程序类的侦听器方法来调度事件。可以通过调用适当的调度程序方法向事件调度程序注册事件处理程序/侦听器。
这显然会导致一些样板代码用于注册每个事件处理程序(以及我的引擎的其他方面都有类似的bolierplate代码),所以我想知道 - 如何在加载事件处理程序期间使用Instrumentation添加所有必需的代码class,因此编码时不需要事件调度程序的显式注册 - 在程序运行时自动添加对调度程序寄存器方法的调用。
我的理解是,为了使用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字节码库:
然而,在进入字节码操作之前,我会考虑其他选项。
将逻辑添加到几个类可能会很无聊,但除非你有很多处理程序,否则这就是我要去的方式。把事情简单化。
那说,
Game.registerHandler( this );
会更加面向对象。
在每个类中添加逻辑的替代方法是引入负责实例化处理程序的工厂。
HandlerFactory.createMouseHandler();
方法createMouseHandler
包含类似的东西
Handler mh = new MousheHandler();
registerHandler(mh);
return mh;
如果你不想要这些选项中的任何一个,我会考虑一个方面框架(可能是AspectJ)或一个控制反转的容器(可能是Spring IoC)。方面允许您注释您的源,并在选定的位置“编织”代码。 IoC容器允许您控制对象的生命周期(例如实例化)。两者都在场景后面使用字节码检测。
但是如果你想自己做仪器,我只能比较我个人使用的Javassist和ASM。
ASM是低级的,并且实际上在java字节码的级别上运行。你必须熟悉它。该框架设计精良,手册非常好,而且它是一个很棒的库。一方面,它可以复杂化以替换字节码的模式,因为它需要所谓的“有状态”转换。另一方面,您可以完全控制字节码。
Javassist更高级。您不是在字节码的原始级别操作,稍高级别,例如字段读/写,消息发送,构造函数。此外,它允许您使用常规Java语法指定更改,然后由框架编译。 API有点混乱,因为该项目多年来不断发展。有关于框架的文档,但没有像ASM那样集中管理。