2010-10-26 16 views
8

Esiste un modo fattibile per far funzionare il mio codice ogni volta che una classe viene caricata in Java, senza forzare esplicitamente l'utente e caricare manualmente tutte le classi con un classloader personalizzato?Come posso eseguire il mio codice al caricamento della classe?

Senza entrare troppo nei dettagli, ogni volta che una classe che implementa una determinata interfaccia legge la sua annotazione che la collega ad un'altra classe e la coppia ad una terza classe.

Modifica: Heck, andrò ai dettagli: Sto facendo una libreria di gestione degli eventi. Quello che sto facendo è che il codice client faccia le proprie coppie Listener/Event, che devono essere registrate con la mia libreria in coppia. (hm, non è stato così tanto tempo dopo).

Ulteriore modifica: Attualmente il codice client deve registrare manualmente la coppia di classi/interfacce, che funziona piuttosto bene. Il mio intento è di automatizzarlo, e ho pensato che collegare le due classi con le annotazioni sarebbe stato d'aiuto. Successivamente, voglio sbarazzarmi del codice cliente che ha bisogno di mantenere sempre aggiornato l'elenco delle registrazioni.

PS: Il blocco statico non funziona, poiché la mia interfaccia è raggruppata in una libreria e il codice client creerà ulteriori interfacce. Quindi, le classi astratte non lo faranno, poiché deve essere un'interfaccia.

+0

Hm, hai provato a utilizzare il blocco di inizializzazione statico? – Kel

risposta

8

Se si desidera basare il comportamento su un'interfaccia, è possibile utilizzare un inizializzatore statico in tale interfaccia.

public interface Foo{ 

    static{ 
     // do initializing here 
    } 

} 

Non sto dicendo che è buona pratica, ma sarà sicuramente inizializzare la prima volta una delle classi di attuazione viene caricato.

Aggiornamento: I blocchi statici nelle interfacce sono illegali. Usa invece le classi astratte!

Riferimento:


Ma se ho capito bene, si vuole l'inizializzazione avvenga una volta per ogni implementazione di classe. Sarà difficile. Non puoi assolutamente farlo con una soluzione basata su interfaccia. Potresti farlo con una classe base astratta che ha un inizializzatore dinamico (o costruttore), che controlla se la mappatura richiesta esiste già e la aggiunge se non lo fa, ma fare cose simili nei costruttori è un bel problema.

Direi che le opzioni più pulite sono generare codice al momento della compilazione (tramite l'elaborazione di annotazioni con apt o tramite l'analisi bytecode con uno strumento come asm) o utilizzare un agente in fase di caricamento della classe per creare dinamicamente il mapping.


Ah, più input. Molto bene. Quindi i client usano la tua libreria e forniscono mappature basate su annotazioni. Quindi direi che la tua libreria dovrebbe fornire un metodo di inizializzazione, in cui il codice client può registrare le classi.Qualcosa di simile a questo:

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

O, meglio ancora, un meccanismo di scansione del pacchetto (codice di esempio per implementare questo può essere trovato at this question):

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

In ogni caso, non v'è praticamente alcun modo per evitare che la i clienti fanno quel tipo di lavoro, perché non puoi controllare il loro processo di compilazione né il loro programma di caricamento classi per loro (ma potresti ovviamente fornire guide per il classloader o la configurazione di build).

+0

(Ho appena aggiunto più informazioni all'OP) i blocchi statici o le classi astratte non funzioneranno. Hai capito bene - questo sarebbe stato fatto per interfaccia client-codice. –

+0

Attualmente sto facendo la registrazione (a parte non ho ancora annotazioni, e sono registrate in coppie definite dal cliente) che funziona bene. Pensato per automatizzare questo. Ma quel metodo di scansione dei pacchetti sembra piuttosto allettante (a parte il refactoring reso più difficile). Darò un'occhiata a quella soluzione. Ahimè, non accettando neanche qui, ancora. –

+1

Rilassati, hai appena fatto la domanda un'ora fa, non c'è bisogno di accettare nulla solo ora. A proposito: anche se lo fai, puoi * non accettare più una risposta più tardi. –

2

Se volete qualche pezzo di codice per essere eseguito su qualsiasi classe di carico, si dovrebbe:

  1. sovrascrivere il ClassLoader, aggiungendo il proprio codice personalizzato ai metodi loadClass (non dimenticate l'inoltro al genitore ClassLoader dopo o prima del tuo codice personalizzato).
  2. Definisci questo ClassLoader personalizzato come predefinito per il tuo sistema (qui puoi vedere come farlo: How to set my custom class loader to be the default?).
  3. Esegui e controlla.

A seconda di quale tipo di ambiente si è, ci sono possibilità che non tutte le classi essere caricati trouugh tua ClassLoader personalizzato (alcuni pacchetti di utilità utilizzano il proprio CL, alcuni contenitori Java EE gestire alcune aree spacific con classloader specifici, ecc.), ma è una sorta di approssimazione a ciò che stai chiedendo.

+0

Grazie. Darò uno scatto. Non accetterò ancora questa risposta, però. –

Problemi correlati