2010-08-21 8 views
6

Come possiamo iniettare manualmente un oggetto senza utilizzare la facilità dei contenitori. Ho fatto qualcosa di simile attraverso la riflessione come segue.In che modo l'iniezione di dipendenza viene implementata manualmente?

Class actionClass = Class.forName("SampleClass"); 
Object actionObject = actionClass.newInstance(); 
Method reqMethod = actionClass.getMethod("setRequest", HttpServletRequest.class); 
reqMethod.invoke(actionObject,request); 

è il modo giusto di fare DI?

La mia intenzione è di passare l'oggetto richiesta a diverse classi di controller dinamicamente da un filtro dispatcher, dove otteniamo oggetti di richiesta e risposta. Sono preoccupato per l'esecuzione della riflessione. C'è qualche sostituto per fare DI?

risposta

0

Iniezione di dipendenza implica l'ottenimento di riferimenti correttamente inizializzati che appaiono "per magia".

Si chiama il metodo setRequest() con l'oggetto richiesta, ma DI consente spesso anche di impostare i campi senza richiamare metodi.

Guice non richiede in genere un contenitore, ma utilizza la magia del caricatore di classi avviata nel metodo principale. Sarebbe utile per te?

+0

Mi piace il termine "per magia". Come sta avvenendo l'inizializzazione. Come è fatto in primavera o in simili contenitori DI. –

+1

L'idea è di spostare l'inizializzazione lontano dalla classe iniettata e dalla classe in cui avviene l'iniezione, in modo che non sappiano come accade. Il punto in cui si sposta il codice di iniezione è quindi dipendente dall'implementazione e, in pratica, non è necessario conoscere. Alla fine si usa il reflection ma è come dire che Hibernate sta usando JDBC alla fine. –

+0

La mia intenzione è di passare l'oggetto richiesta a diverse classi di controller dinamicamente da un filtro dispatcher, dove otteniamo oggetti di richiesta e risposta. –

5

L'iniezione di dipendenza non è altro che fornire una classe con le sue dipendenze, piuttosto che trovarla da sé (tramite singleton/lookup, ecc.). Quindi puoi farlo in codice banalmente così:

DatabaseConnection dc = new DatabaseConnection(); 
MyDAO dao = new MyDAO(dc); 

(pseudocodice). Qui MyDAO viene iniettato con una connessione al database. Se questa connessione al database implementa un'interfaccia, puoi facilmente deriderla durante i test.

2

Bene, quando si imposta un oggetto in un altro oggetto utilizzando il metodo setter o tramite un costruttore, è anche l'iniezione della dipendenza. Iniezione di dipendenza significa solo creare una relazione (dipendenza) negli oggetti.

L'uso del riflesso come hai fatto è solo un'altra forma di esso.

1

Perché utilizzare la riflessione? Perché non è sufficiente:

SampleClass action = new SampleClass(); 
action.setRequest(request); 

che fa la stessa cosa, ma è più leggibile, consente al compilatore di verificare che in realtà esistono i tipi e metodi, si dà Javadoc per il metodo invocato, permette il vostro IDE per aiutare a refactoring, ...

E ancora è l'iniezione di dipendenza, perché l'azione non va in cerca della sua richiesta, ma riceve la richiesta durante l'inizializzazione.

Modifica: Thorbjørn ha richiesto di mostrare come questa azione sarebbe stata utilizzata. Sarebbe esso stesso iniettato (usando un setter) in qualunque componente utilizzasse l'azione. Il componente utilizzerà quindi l'oggetto azione iniettato.

SampleClass action = new SampleClass(); 
action.setRequest(request); 
Servlet servlet = new ActionBasedServlet(); 
servlet.setAction(action); 

Se servlet destinato a vivere più a lungo action, cioè esso dovrebbe utilizzare un nuovo Action ogni volta che deve uno, si può invece setter-iniettare un ActionFactory in servlet.

In questo caso concreto, mi chiedevo se l'azione ha davvero bisogno di mantenere una richiesta come parte del suo stato, o può essere immutabile e semplicemente agire sulla richiesta passata dal Servlet come parametro del metodo.In tal caso, l'inizializzazione all'avvio farebbe:

SampleClass action = new SampleClass(); 
Servlet servlet = new ActionBasedServlet(); 
servlet.setAction(action); 

e ActionBasedServlet definirebbe

public void serve(Request req, Response resp) { 
    foo(); 
    action.act(req, resp); 
    bar(); 
} 
+0

La parola chiave 'new' fornisce un binding estremamente forte dalla classe corrente a quella new'ed. Iniezione di dipendenza _decupate_ questo forte legame tra i due. –

+3

L'iniezione di dipendenza disaccoppia il componente dalle sue dipendenze. Ciò non significa che non ci debba essere un'altra parte del codice che sappia sia il componente che la sua dipendenza. SampleClass non è accoppiato alla particolare richiesta nel mio esempio. – meriton

+0

Nel mio caso, il nome della classe è dinamico. Per creare un DI comune per tutte le classi. cioè perché ho usato la riflessione. grazie per la tua risposta. –

0

framework Spring è una delle implementazioni più popolari DI. È anche opensource. È possibile controllare la classe org.springframeowrk.beans.BeanUtils, in particolare i metodi copyProperties (tutti e 4 di essi) per gli esempi su come farlo. Per ulteriori informazioni è inoltre possibile visualizzare la gerarchia di classi di org.springframework.beans.factory.BeanFactory per diverse strategie.

Problemi correlati