2011-04-09 5 views
10

Ho lavorato con una base di codice di una società che ha una politica di scrittura di molte registrazioni di traccia. Così praticamente ogni metodo ha un pezzo di codice che inizia così:Utilizzo di annotazioni per la registrazione di traccia

String LOG_METHOD = "nameOfMethod(String,List<Long>):void"; 
if(logger.isTraceEnabled()) { 
    Object[] params = new Object[] { string, list }; 
    logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params)); 
} 

e alla fine come questo (o in un finally -clause o solo alla fine del metodo:

if(logger.isTraceEnabled()) { 
    logger.trace(CompanyMessages.leaveMethodInstanceMessage(this, LOG_METHOD)); 
} 

Ci è in realtà più codice, ma questa è l'idea di base Questo è il cluttering del codice e altri codificatori sono costantemente in disordine con le proprie interpretazioni che non utilizzano la specifica classe CompanyMessages necessaria per formattare i messaggi in essere letto dagli strumenti di monitoraggio, quindi sto cercando un modo per sbarazzarsi di il codice precedente e forniamo tutti i metodi che richiedono la registrazione di traccia con annotazioni come: @LogBefore('logLevel')@LogAfter('logLevel').

Il motivo per cui scelgo questa soluzione è di farlo in modo che gli altri sviluppatori non debbano imparare nulla di nuovo ma utilizzare le annotazioni anziché il codice. Sto lavorando in un ambiente server in cui distribuiamo centinaia di applicazioni Web e dozzine di sviluppatori. Quindi ho cercato un modo per implementarlo in un'applicazione web senza un sacco di codice aggiuntivo o librerie aggiuntive di grandi dimensioni. Ciò significa che sto cercando un'implementazione AOP piccola e stabile utilizzando annotazioni simili a quelle che ho proposto, facili da configurare in ogni applicazione web. Anche le prestazioni sono importanti. Qual è l'esempio più semplice per implementarlo con AOP?

Modifica: ho trovato something very similar per quello che sto cercando, ma questo ha un paio di problemi. Tutte le classi che richiedono la registrazione devono essere configurate, il che comporterebbe un dispendio di risorse maggiore rispetto all'uso delle annotazioni. La configurazione della molla <aop:aspectj-autoproxy/> la risolverebbe?

risposta

3

Non penso che le annotazioni fossero la soluzione. Annotare una classe o un'istanza significa dare alle classi informazioni aggiuntive in fase di runtime, di per sé non fa nulla. Avresti bisogno di un codice che elabori le classi con annotazioni e aggiunga codice prima e dopo ciascun metodo basato su tali annotazioni durante il runtime.

Quindi non c'è modo di aggiungere annotazioni e pronto per andare, le classi iniziano a registrare i loro metodi.

La soluzione deve essere AOP: questo è esattamente il problema AOP è stato inventato in primo luogo. Definisci classi/metodi/azioni su ciascun metodo e risolvi il problema.

Beh, probabilmente è possibile farlo funzionare con le annotazioni e le classi che modificano durante il runtime, ma si finisce con sé fatto AOP :-)

+0

Grazie, questo mi ha fatto capire che il mio punto di vista sul funzionamento delle annotazioni era difettoso. – mahler

5

Sembra Aspect Oriented Programming (AOP) potrebbe davvero aiutare con questo. È ottimo per risolvere questi problemi trasversali come la registrazione e la traccia e supporta annotazioni come quelle che ti servono.

Dai un'occhiata a AspectJ o Spring AOP.

Ciò comporterà un po 'di apprendimento dei principi AOP e dell'API che hai scelto, ma ne vale sicuramente la pena. Soprattutto la registrazione e il tracciamento sono tra i primi tutorial AOP che incontrerai ed è abbastanza facile da fare senza dover andare più a fondo.

4

Le annotazioni e i punti AOP sono entrambi validi. Utilizzare le annotazioni per avvisare il framework AOP sulla registrazione.

Un'altra cosa che vorrei fare è correggere il logger.

si dispone di:

String LOG_METHOD = "nameOfMethod(String,List<Long>):void" 
if(logger.isTraceEnabled()) { 
    Object[] params = new Object[] { string, list }; 
    logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params)); 
} 

Invece, di qualcosa di simile:

logger.trace(this, LOG_METHOD, string, list); 

e si può implementare in questo modo:

public void trace(Object obj, Object args...) { 
    if (parentLogger.isTraceEnabled()) { 
     logger.trace(CompanyMessages.newMethodInstanceMessage(obj, LOG_METHOD, args); 
    } 
} 

La maggior parte dei programmi di utilità di registrazione sono stati scritti prima di avere vararg in Java, quindi vediamo ancora cose come quello che hai scritto.

Inoltre abbiamo ancora voglia la guardia per evitare che registro chiamate quando non è attivato, ma la motivazione principale di ciò è perché la maggior parte la gente in passato avrebbero fatto quello che hai fatto, o, peggio ancora:

logger.trace("My message: " + string + " with list " + list); 

Quale ha un'espressione costosa se la traccia è abilitata o meno.

Ma sfruttando vararg, è possibile ottenere entrambi. Basta usare qualcosa come MessageFormat (che probabilmente si sta facendo già), si può facilmente ottenere:

logger.trace("My message: {0} with list {1}", string, list); 

Con traccia disabilitata, questo è un metodo a basso costo chiamata passando 3 puntatori. Quindi c'è molta meno motivazione a proteggerlo e ingombrare il tuo codice.

La maggior parte dei moderni logger non si sovrappone bene, quindi in genere è necessario incapsularla anziché semplicemente estenderla.

Non risolve direttamente il problema, generando dinamicamente le informazioni di traccia. Ma è una semplice via di mezzo che prontamente e in modo incrementale ripulisce il tuo codice esistente.

Inoltre, ci sono altre 2 opzioni.

Uno, è utilizzare un post processore che esegue il codice e aggiunge l'accesso a luoghi in cui non esiste già. Ciò ti risparmia l'onere di digitare tutto a mano, ma ingombra il codice (poiché esiste ancora OVUNQUE).

Due, è utilizzare un processore di annotazione in fase di compilazione. Questo è più sofisticato. Ma quello che fa è durante la compilazione, scorre e aumenta le tue lezioni in fase di compilazione con le informazioni. La cosa bella è che il tuo codice è pulito (tranne forse per l'annotaione), ma anche tutto il lavoro è fatto alla compilazione. Non c'è impatto di runtime sui classloader di fantasia delle fabbriche di oggetti. Una volta che è stato creato, puoi gettare via il tuo processore, non è affatto necessario in fase di runtime.

C'è un progetto, il cui nome mi sfugge, che fa leva su questo. Compila automaticamente setter/getter per il tuo codice al momento della compilazione. Ho sentito cose positive a riguardo.

I framework AOP potrebbero farlo al momento della compilazione, non ho abbastanza familiarità con loro da dire, ma in entrambi i casi, la tecnica merita di essere esplorata.

Come minimo, tuttavia, avvolgere il registratore. È incrementale, sicuro e pulirà gradualmente il codice e faciliterà la registrazione in cui le annotazioni potrebbero non funzionare in generale.