Java Dynamic Proxy

Il proxy è un design pattern strutturale in cui un oggetto P funge da mediatore nelle chiamate verso un altro oggetto O. In altri termini un chiamante non invocare direttamente i metodi dell’oggetto O, ma lo fa attraverso l’intermediazione di un terzo attore P che si occupa di invocare concretamente i metodi sull’oggetto originale, e di restituire i risultati dell’invocazione in caso di metodi con valori di ritorno. L’esempio che generalmente viene riportato dalla letteratura specializzata è quello dell’utilizzo di una risorsa su disco, il cui caricamento in memoria è differito sino all’utilizzo vero e proprio della risorsa. Al link Design Patterns – Proxy Pattern trovate una implementazione del pattern per la gestione di immagini. Le classi proxy possono essere utilizzate per diversi scopi. Un elenco non esaustivo è il seguente:

  • Registrazione quando un metodo inizia e finisce.
  • Eseguire controlli aggiuntivi sugli argomenti.
  • Mokkare il comportamento della classe originale.
  • Implementare accesso lazy a risorse costose.

Implementazione

Di solito gli oggetti proxy hanno gli stessi metodi dell’oggetto originale e nelle implementazioni con Dynamic Proxy java estendono esplicitamente (extends) la classe originale. La gestione delle chiamate avviene attraverso uno o più handler, che possono o meno invocare il metodo originale. 

La classe java.lang.reflect.Proxy espone diversi metodi statici per la manipolazione dei proxy dinamici. In particolare i metodi getProxyClass e newProxyInstance possono essere utilizzati rispettivamente per generare una classe proxy per una dato set di interfacce o la relativa istanza. Ad ogni istanza di un proxy deve essere associato un oggetto handler che implementa l’interfaccia java.lang.reflect.InvocationHandler. Ogni invocazione di un metodo sull’istanza del proxy viene intercettata dal metodo invoker() dell’handler, al quale è passata l’istanza (del proxy), il metodo invocato ed un array contenente gli argomenti di invocazione.

Una nuova istanza di proxy è quindi generata nel modo seguente:

o più semplicemente.

Esempio

L’esempio che presentiamo è quello di un proxy che estende le funzionalità di un logger per inserire in tutti i messaggi una componente comune che identifica tutte le chiamate ad un servizio web. Nell’articolo JAX-WS Interceptor abbiamo visto come sia possibile intercettare le chiamate ad un web service implementato con JAX-WS al fine di memorizzare in un oggetto ThreadLocal la componente Header della Request. Quello che faremo è di intercettare le chiamate al log e di inserire nel messaggio il sender della request, in questo modo ogni stringa di log sarà riconducibile al chiamante.

Nel dettaglio l’esempio utilizza il logger org.slf4j.Logger e attraverso la corrispondente classe factory org.slf4j.LoggerFactory genera un logger “wrappandolo” all’interno di un dynamic proxy. A tale scopo è implementato un handler il cui costruttore riceve in input il logger generato:

Il metodo invoke(), richiesto dall’interfaccia InvocationHandler, verifica che il metodo invocato sia uno tra debug, trace, warn ed error esposti dal dall’oggetto Logger ed in caso affermativo modifica l’argomento di input inserendo nel messaggio il sender:

Codice Sorgente

Il codice sorgente dell’esempio è scaricabile qui jaxws-webapp-proxy.

How useful was this post?

Click on a star to rate it!

Average rating / 5. Vote count:

No votes so far! Be the first to rate this post.

As you found this post useful...

Follow us on social media!