2012-04-18 18 views
11

Escribo un motor/biblioteca de juegos en el cual tengo una clase de despachador de eventos que distribuye eventos llamando métodos de escucha de clases de manejadores de eventos "registrados". Se puede registrar un controlador/oyente de eventos con el despachador de eventos llamando al método de despachador apropiado.Agregar código a una clase Java con Instrumentación: ¿ASM o BCEL?

Esto obviamente conduce a un código repetitivo para registrar cada controlador de eventos (y también otros aspectos de mi motor tienen código de placa base similar), así que me preguntaba: ¿qué tal usar Instrumentación para agregar todo el código necesario durante la carga de la clase de controlador de eventos, de modo que no es necesario un registro explícito con el despachador de eventos durante la codificación: la llamada al método de registro del despachador se agrega automáticamente cuando se ejecuta el programa.

Tengo entendido que para utilizar la instrumentación se debe utilizar alguna API de modificador de bytecode. Conozco dos: ASM y BCEL. ¿Cuál debería usar? Obviamente, esta es una tarea algo simple que estoy tratando de hacer, por lo que quiero la que sea más fácil de aprender y documentar mejor.

EDITAR: Aquí hay un ejemplo específico.

original clase de controlador de eventos:

@Handler //indicates this this class should be transformed 
public class MouseEventHandler implements EventHandler<MouseEvent> 
{ 
    //hidden default constructor 
    public void handleEvent(MouseEvent event) 
    { ... } 
} 

Después de la transformación:

@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) 
    { ... } 
} 

Respuesta

20

Sin embargo, consideraría otras opciones antes de saltar a la manipulación de bytecode.

+0

bcel se ha incluido en JDK –

+1

@ alexander.box: Sí, como una dependencia del transformador XSLTC Xalan, pero es una API no estándar y también está oculta en el paquete com.sun.org.apache.bcel.internal ! Mejor provee tu propio frasco. – Daniel

+2

Ah, y mientras estoy en ello: ASM es una muy buena opción cuando las clases tienen que ser instrumentadas. Fácil de entender y usar También tiene una documentación muy buena. – Daniel

6

Agregar la lógica a algunas clases puede ser aburrido, pero a menos que tenga miles de manipuladores, ese es el camino que seguiría. Mantenlo simple.

Dicho esto,

Game.registerHandler(this); 

habría más orientado a objetos.

Una alternativa para agregar la lógica en cada clase es introducir una fábrica que es responsable de crear instancias de los controladores.

HandlerFactory.createMouseHandler(); 

y el método createMouseHandler contiene algo así como

Handler mh = new MousheHandler(); 
registerHandler(mh); 
return mh; 

Si no desea ninguna de estas opciones, consideraría ya sea un marco aspecto (tal vez AspectJ) o un recipiente para Invertion of Control (quizás Spring IoC). Los aspectos te permiten anotar tu fuente y "tejer" el código en los lugares seleccionados. Un contenedor IoC le permite controlar el ciclo de vida de un objeto (por ejemplo, creación de instancias). Ambos usan instrumentación bytecode detrás de la escena.

Pero si usted quiere hacer la instrumentación usted mismo, solo puedo comparar Javassist y ASM que utilicé personalmente.

ASM es de bajo nivel, y funciona realmente en el nivel de bytecode java. Debes estar familiarizado con esto. El marco está muy bien diseñado, el manual es excelente y es una gran biblioteca. Por un lado, puede ser complicado reemplazar los patrones de bytecode, ya que requiere una transformación llamada "con estado". Por otro lado, usted tiene control total sobre el bytecode.

Javassist es de más alto nivel. No opera en el nivel básico de bytecode, un nivel ligeramente superior, p. campos de lectura/escritura, envío de mensajes, constructores. Además, le permite especificar cambios usando la sintaxis regular de Java, que luego es compilada por el marco. La API está un poco confundida, porque el proyecto creció a lo largo de los años. Existe documentación sobre el marco, pero no tan bien centralizada como con ASM.

Cuestiones relacionadas