Java Reflection-Proxy dinamici

Utilizzando Java Reflection si creano implementazioni dinamiche di interfacce in fase di runtime. Lo fai usando la classe java.lang.reflect.Proxy. Il nome di questa classe è il motivo per cui mi riferisco a queste implementazioni di interfaccia dinamica come proxy dinamici. I proxy dinamici possono essere utilizzati per molti scopi diversi, ad esempio connessione al database e gestione delle transazioni, oggetti simulati dinamici per il test delle unità e altri scopi di intercettazione dei metodi simili a AOP.

Creazione di proxy

Si creano proxy dinamici utilizzando il metodo Proxy.newProxyInstance(). Il newProxyInstance() metodi prende 3 parametri:

  1. Il ClassLoader che deve “caricare” la classe proxy dinamica.
  2. Una serie di interfacce da implementare.
  3. An InvocationHandler per inoltrare tutte le chiamate ai metodi sul proxy.

Ecco un esempio:

Dopo aver eseguito questo codice la variabile proxy contiene un’implementazione dinamica dell’interfaccia MyInterface. Tutte le chiamate al proxy verranno inoltrate all’implementazione handler dell’interfaccia generale InvocationHandler. InvocationHandler sono coperti i la prossima sezione.

Invocationhandler’s

Come accennato in precedenza, è necessario passare un’implementazione InvocationHandler al metodo Proxy.newProxyInstance(). Tutte le chiamate al metodo al proxy dinamico vengono inoltrate a questa implementazione InvocationHandler. Ecco come appare l’interfaccia InvocationHandler :

public interface InvocationHandler{ Object invoke(Object proxy, Method method, Object args) throws Throwable;}

Ecco un esempio di implementazione:

public class MyInvocationHandler implements InvocationHandler{ public Object invoke(Object proxy, Method method, Object args) throws Throwable { //do something "dynamic" }}

Il parametro proxy passato al metodo invoke() è l’oggetto proxy dinamico che implementa l’interfaccia. Molto spesso non hai bisogno di questo oggetto.

L’oggetto Method passato nel metodo invoke() rappresenta il metodo chiamato sull’interfaccia implementata dal proxy dinamico. Dall’oggetto Method è possibile ottenere il nome del metodo, i tipi di parametro, il tipo di ritorno, ecc. Vedere il testo sui metodi per ulteriori informazioni.

L’array Object args contiene i valori dei parametri passati al proxy quando è stato chiamato il metodo nell’interfaccia implementata. Nota: le primitive (int, long ecc.) nell’interfaccia implementata sono racchiuse nelle loro controparti oggetto (Integer, Long ecc.).

Noti Casi di Utilizzo

Dynamic proxy sono noti per essere utilizzato almeno per i seguenti scopi:

  • Connessione al Database e la Gestione delle Transazioni
  • Dinamica di Oggetti fittizi per i Test di Unità
  • Adattamento DI Contenitore per Custom Factory Interfacce
  • AOP-come Metodo di Intercettazione

Connessione al Database e la Gestione delle Transazioni

Il framework Spring dispone di una transazione proxy in grado di avviare e commit / rollback di una transazione. Come funziona è descritto in modo più dettagliato nel testo Advanced Connection and Transaction Demarcation and Propagation, quindi lo descriverò solo brevemente. La sequenza di chiamate diventa qualcosa di simile:

Oggetti Mock dinamici per il test delle unità

Gli strumenti di test Butterfly utilizzano proxy dinamici per implementare stub dinamici, mock e proxy per il test delle unità. Quando si verifica una classe A che utilizza un’altra classe B (interfaccia in realtà), è possibile passare una finta implementazione di B in A invece di una vera B. Tutte le chiamate al metodo su B sono ora registrate e puoi impostare i valori di ritorno che il finto B deve restituire.

Inoltre gli strumenti di test Butterfly consentono di avvolgere un vero B in un finto B, in modo che tutte le chiamate al metodo sul finto siano registrate e quindi inoltrate al vero B. Ciò consente di verificare quali metodi sono stati chiamati su un reale funzionamento B. Ad esempio, se si verifica un DAO è possibile avvolgere la connessione al database in Il DAO non vedrà la differenza e il DAO può leggere / scrivere dati nel database come al solito poiché il finto inoltra tutte le chiamate al database. Ma ora puoi controllare tramite il mock se il DAO usa correttamente la connessione, ad esempio se connection.close() è chiamato (o NON chiamato), se te lo aspettavi. Questo normalmente non è possibile determinare dal valore restituito di un DAO.

Adattamento del contenitore DI alle interfacce di fabbrica personalizzate

Il contenitore per iniezione di dipendenza Butterfly Container ha una potente funzionalità che consente di iniettare l’intero contenitore nei bean prodotti da esso. Ma, dal momento che non si desidera una dipendenza dall’interfaccia del contenitore, il contenitore è in grado di adattarsi a un’interfaccia di fabbrica personalizzata del proprio progetto. Hai solo bisogno dell’interfaccia. Nessuna implementazione. Quindi l’interfaccia di fabbrica e la tua classe potrebbero assomigliare a questo:

public interface IMyFactory { Bean bean1(); Person person(); ...}

Quando la classe MyAction chiama i metodi sull’istanza IMyFactory iniettata nel suo costruttore dal contenitore, le chiamate al metodo vengono tradotte in chiamate al metodo IContainer.instance(), che è il metodo utilizzato per ottenere istanze dal contenitore. In questo modo un oggetto può utilizzare il Contenitore Butterfly come factory in fase di runtime, piuttosto che solo per avere dipendenze iniettate in se stesso al momento della creazione. E questo senza avere alcuna dipendenza da qualsiasi interfaccia specifica del contenitore Butterfly.

Intercettazione del metodo simile a AOP

Il framework Spring consente di intercettare le chiamate al metodo a un determinato bean, a condizione che bean implementi un’interfaccia. Il framework Spring avvolge il bean in un proxy dinamico. Tutte le chiamate al bean vengono quindi intercettate dal proxy. Il proxy può decidere di chiamare altri metodi su altri oggetti prima, anziché o dopo aver delegato la chiamata al metodo al bean avvolto.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.