2010-10-26 13 views
8

¿Hay alguna manera factible de ejecutar mi propio código cada vez que se carga una clase en Java, sin forzar al usuario a cargar todas las clases de forma explícita y manual con un cargador de clases personalizado?¿Cómo puedo ejecutar mi código al cargar la clase?

Sin entrar demasiado en los detalles, cada vez que una clase que implementa una determinada interfaz lee su anotación que lo vincula con otra clase, y le da el par a una tercera clase.

Editar: Diablos, voy a ir a detalles: estoy haciendo una biblioteca de manejo de eventos. Lo que estoy haciendo es hacer que el código del cliente haga sus propios pares de Escucha/Evento, que deben registrarse con mi biblioteca como un par. (hm, eso no fue tan largo después de todo).

Further Edit: Actualmente, el código del cliente necesita registrar el par de clases/interfaces manualmente, lo que funciona bastante bien. Mi intención es automatizar esto, y pensé que vincular las dos clases con anotaciones ayudaría. Luego, quiero deshacerme del código del cliente que necesita mantener la lista de registros actualizada siempre.

PS: El bloque estático no funcionará, ya que mi interfaz está incluida en una biblioteca, y el código del cliente creará más interfaces. Por lo tanto, las clases abstractas tampoco funcionarán, ya que debe ser una interfaz.

+0

Hm, ¿intentó utilizar el bloque de inicialización estática? – Kel

Respuesta

8

Si desea basar el comportamiento en una interfaz, puede usar un inicializador estático en esa interfaz.

public interface Foo{ 

    static{ 
     // do initializing here 
    } 

} 

No estoy diciendo que es una buena práctica, pero no cabe duda de inicializar la primera vez que una de las clases que implementan se carga.

Actualización: bloques estáticos en las interfaces son ilegales. ¡Utiliza clases abstractas en su lugar!

Referencia:


Pero si le he entendido bien, desea que la inicialización ocurra una vez por la implementación de la clase. Eso será complicado. Definitivamente no puedes hacer eso con una solución basada en interfaz. Podrías hacerlo con una clase base abstracta que tenga un inicializador dinámico (o constructor), que verifique si el mapeo solicitado ya existe y lo agrega si no lo hace, pero hacer tales cosas en los constructores es todo un truco.

Diría que las opciones más limpias son generar código en tiempo de compilación (mediante el proceso de anotación con apt o mediante análisis de bytecode con una herramienta como asm) o usar un agente en el tiempo de carga de clase para crear dinámicamente la asignación.


Ah, más de entrada. Muy bien. Entonces los clientes usan su biblioteca y proporcionan asignaciones basadas en anotaciones. Entonces diría que su biblioteca debería proporcionar un método de inicialización, donde el código del cliente puede registrar clases.Algo como esto:

YourLibrary.getInstance().registerMappedClasses(
    CustomClass1.class, 
    CustomClass2.class, 
    CustomClass3.class, 
    CustomClass4.class 
) 

O, mejor aún, un mecanismo de lectura óptica de paquetes (código de ejemplo para implementar esto se puede encontrar at this question):

YourLibrary.getInstance().registerMappedClassesFromPackages(
    "com.mycompany.myclientcode.abc", 
    "com.mycompany.myclientcode.def" 
) 

De todos modos, prácticamente no hay manera de evitar que su los clientes hacen ese tipo de trabajo, porque no puedes controlar su proceso de compilación ni su cargador de clases (pero, por supuesto, podrías proporcionar guías para el cargador de clases o la configuración de compilación).

+0

(acaba de agregar más información al OP) bloques estáticos o clases abstractas no funcionarán. Entendiste bien, esto se haría por interfaz de código de cliente. –

+0

Estoy haciendo el registro actualmente (excepto que todavía no tengo anotaciones, y están registradas en parejas definidas por el cliente) que funciona bien. Pensé en automatizar esto. Pero ese método de escaneo de paquetes parece bastante atractivo (aparte de la refactorización hecha más difícil). Echaré un vistazo a esa solución. Por desgracia, tampoco aceptar aquí, todavía. –

+1

Relájate, acabas de hacer la pregunta hace una hora, no hay necesidad de aceptar nada ahora. Por cierto: incluso si lo haces, * puedes * no aceptar una respuesta más tarde. –

2

Si desea alguna pieza de código que se ejecuta en cualquier carga de clases, usted debe:

  1. sobrescribir el cargador de clases, añadiendo su propio código personalizado en los métodos loadClass (no se olvide de reenvío a los padres ClassLoader después o antes de su código personalizado).
  2. Defina este ClassLoader personalizado como el predeterminado para su sistema (aquí tiene cómo hacerlo: How to set my custom class loader to be the default?).
  3. Ejecutar y verificarlo.

Dependiendo de qué tipo de medio ambiente que son, hay posibilidades de que no todas las clases pueden cargar trouugh el cargador de clases personalizado (algunos paquetes de servicios públicos utilizan su propio CL, algunos contenedores Java EE manejar algunas áreas spacific con cargadores de clases específicas, etc.), pero es una especie de aproximación a lo que estás preguntando.

+0

Gracias. Voy a dar una oportunidad. Sin embargo, no aceptaré esta respuesta todavía. –

Cuestiones relacionadas