2009-02-23 13 views
16

Voglio intercettare tutte le chiamate di metodi in qualche classe MyClass per poter reagire su alcune chiamate setter.Come si intercetta un richiamo del metodo con funzioni java standard (senza AspectJ, ecc.)?

Ho provato a utilizzare i proxy dinamici, ma per quanto ne so, questo funziona solo per le classi che implementano alcune interfacce. Ma MyClass non ha una tale interfaccia.

C'è un altro modo, oltre all'implementazione di una classe wrapper, che delega tutte le chiamate a un membro, che è un'istanza di MyClass o besided utilizzando AOP?

risposta

23

Come si nota, non è possibile utilizzare proxy dinamici JDK (senza interfaccia), ma utilizzando Spring e CGLIB (JAR incluso in primavera), è possibile effettuare le seguenti operazioni:

public class Foo 
{ 
    public void setBar() 
    { 
     throw new UnsupportedOperationException("should not go here"); 
    } 

    public void redirected() 
    { 
     System.out.println("Yiha"); 
    } 
} 

Foo foo = new Foo(); 
ProxyFactory pf = new ProxyFactory(foo); 

pf.addAdvice(new MethodInterceptor() 
{ 
    public Object invoke(MethodInvocation mi) throws Throwable 
    { 
     if (mi.getMethod().getName().startsWith("set")) 
     { 
      Method redirect = mi.getThis().getClass().getMethod("redirected"); 
      redirect.invoke(mi.getThis()); 
     } 
     return null; 
    } 
}); 

Foo proxy = (Foo) pf.getProxy(); 
proxy.setBar(); // prints "Yiha" 
+0

Grazie! Ho salvato la mia giornata. –

+0

Durante l'intercettazione di un metodo, è possibile leggere gli argomenti passati? – aryaxt

+0

sì che è possibile ... per oggetto (arg: mi.getArguments()) { \t \t \t \t sysout (arg.getClass() + "-" + arg); \t \t \t} – Skabdus

13

Se siete disposti a fare qualcosa di veramente brutto, uno sguardo a:

http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/

In sostanza l'interfaccia debugger dovrebbe consentire di collegare come un debugger, e quindi intercettare le chiamate. Tenete a mente che questa è una pessima idea di , ma avete chiesto se fosse possibile.

+8

+1 per valore di attacco –

+0

concordato. Abbastanza brutto. – Jus12

0

Non c'è molta magia in AspectJ. Puoi scrivere il tuo agente. http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html sembra essere un buon punto di partenza.

+1

Penso che tu sottovaluti il ​​lavoro necessario per gli agenti di qualità di produzione. –

+0

Scusa, non intendevo togliere alcun credito ad AspectJ. È una cosa meravigliosa e la sto usando molto bene. Volevo solo dire che un semplice agente per intercettare i metodi non è molto difficile da scrivere. Grazie per avermi corretto. –

2

Java non ha caratteristiche del linguaggio effettivi per il metodo di intercettazione (non sono sicuro qualsiasi linguaggio statico fa)

ho un po 'come l'idea di Nick di utilizzare l'interfaccia debugger, questo è solo dire.

Penso che la risposta breve di cui hai bisogno è: No, non c'è un modo per intercettare una chiamata di metodo in Java senza effettivamente sostituire la classe usando un proxy o un wrapper.

Nota: le librerie AOP consentono di eseguire automaticamente questa operazione.

1

Alcuni dei guru di Java potrebbero disapprovarlo, ma ho avuto un buon successo evitando completamente i tipi primitivi e setter. La mia classe si presenta così:

class Employee extends SmartPojo { 
    public SmartString name; 
    public SmartInt age; 
} 

Noterai due cose: 1. tutto è pubblico. 2. Nessun costruttore.

La magia si verifica in SmartPojo che cerca qualsiasi campo che implementa l'interfaccia "Smart" e lo inizializza. Poiché non si tratta di una primitiva (e non di una classe finale), è possibile aggiungere i metodi set() e get() per tutti i campi in qualsiasi punto del mio modello in un unico punto. Quindi niente più setter/getter spreca più, è straordinariamente semplice aggiungere notifiche (anche in un singolo posto), ecc.

Vero, questo non è più un POJO e non è un fagiolo in molti modi, ma ho scoperto che questi le vecchie idee mi limitano di più che aiutano. YMMV.

+0

questo è fondamentalmente ciò che Grails fa con i loro oggetti dominio. Tuttavia, poiché possono implementarlo con groovy, è molto più bello e non è necessario disporre di tutte le proprietà che implementano un'interfaccia "intelligente". – Chii

+0

Avevo bisogno di una soluzione solo Java. L'ho provato anche con Groovy e, sebbene il codice sia molto più compatto, non è così bello. Sono un grande fan di Groovy ma sento che 1.x è ancora un po '... "incompleto". –

+0

Puoi condividere il codice per 'SmartPojo'? –

0
  1. Perché la classe non può implementare un'interfaccia? Si può semplicemente estrarre un'interfaccia da esso contenente tutti i metodi che si desidera intercettare e utilizzare facilmente il meccanismo dei proxy dinamici. È anche una buona pratica di programmazione codificare con interfacce e non classi.

  2. È possibile utilizzare il framework Spring con funzionalità Spring AOP (che utilizzano i proxy dinamici interni) per farlo.Dovrai solo definire la tua classe come bean Spring nel file di configurazione e i client della tua classe dovranno ottenere la sua istanza dal contesto dell'applicazione Spring o come dipendenza automaticamente (definendo il metodo setMyClass (MyClass mc) per esempio). Da lì puoi facilmente andare a definire un aspetto che intercetta tutte le chiamate di metodo a questa classe.

+0

Forse sta cercando di eseguire il debug di una classe che non ha scritto contenuta in alcune librerie di terze parti? –

0

Per l'intercettazione della invocazione del metodo java, AspectJ è un ottimo strumento da utilizzare. Attraverso il quale è possibile intercettare le chiamate mthod, le esecuzioni ecc. In modo efficiente. Sto utilizzando lo stesso strumento per intercettare le chiamate al metodo java. Possiamo applicare i pointcuts e gli aspetti ansd per intercettare qualsiasi chiamata al metodo java. per informazioni semplici leggere this

Problemi correlati