2012-11-06 12 views
9

Mi piacerebbe creare un modulo che lega dinamicamente le istanze alle annotazioni con nome. Il caso d'uso è che vorrei associare automaticamente i valori nella mia configurazione con la chiave nel file delle proprietà che è il valore @Named.Come si creano associazioni dinamiche in Guice che richiedono un'istanza iniettata?

Tuttavia, la configurazione è associata a un modulo diverso, pertanto è necessario iniettare la configurazione. Le soluzioni che ho esaminato sono:

  1. Collegamento nel metodo configure(). Questo metodo non è stato iniettato e non posso ottenere la configurazione di base.

  2. Utilizzo di un Provider/@ Fornisce. I provider associano solo una singola istanza.

  3. Utilizzo di MultiBinder. Il mio caso d'uso è leggermente diverso da quello fornito da questa estensione. L'associazione multipla consente di associare più istanze separatamente e quindi di inserirle come una raccolta di tipo più complesso. Vorrei associare ogni istanza separatamente e averli identificabili in modo univoco per l'ultimo caso.

  4. Utilizzare un iniettore per bambini. Purtroppo questo non è possibile senza alcune modifiche estensive del codice esistente. This answer è una buona descrizione di come risolvere questo problema in questo modo.

  5. Iniettare il raccoglitore in qualche modo. (Ho iniziato ad avere un po 'di hacker) Guice permette di iniettare l'iniettore per l'ultimo utilizzo, ho provato a iniettare il raccoglitore nel modulo attraverso un metodo @Provides e poi usando il raccoglitore direttamente per creare legature multiple all'interno del metodo. Guice non avrebbe iniettato il legante.

risposta

8

Ricordate che tutte dei configure metodi configurare tutte degli attacchi in un Injector prima qualsiasi iniezione può accadere. Detto questo, un paio di cose:

  1. Binding @Named proprietà al contenuto di una singola istanza Properties è così utile, c'è un metodo Names.bindProperties(...) che lo fa automaticamente per voi. L'unico trucco è che è necessario eseguire l'istanza Properties all'ora configure().

    Se sono tutti disponibili allo stesso tempo, non preoccuparti di associare le proprietà in un modulo e legare l'applicazione in un altro. Fintanto che entrano tutti nello stesso Injector, Guice li combinerà tutti e lascerà che soddisfino le reciproche dipendenze.

  2. I provider possono restituire istanze diverse e in genere lo fanno, ma hai ragione che non ti aiuta a differenziare le chiavi. Se l'iniezione l'istanza Proprietà direttamente è troppo brutto, considerare la possibilità di una fabbrica leggero invece:

    public class ConfigOracle { 
        @Inject private Properties properties; 
    
        public String getAsString(String key) { ... } 
        public int getAsInt(String key) { ... } 
    } 
    
    public class SomeConfigUser { 
        @Inject private ConfigOracle configOracle; 
    
        public void doStuff() { 
        doStuffBasedOn(configOracle.getAsString("my.properties.key")); 
        } 
    } 
    
  3. non si dovrebbe mai bisogno di iniettare un Binder (o qualsiasi altra cosa) in un modulo.

    • Se si implementa Module, il binder sarà un parametro di configure(). Se estendi AbstractModule come dovresti, chiama il metodo binder().
    • È possibile passare le dipendenze tramite gli argomenti del costruttore al modulo, se necessario, che (per quanto mi riguarda) è l'unico modo in cui i moduli devono variare i collegamenti creati.
    • Non c'è motivo per cui non è possibile creare un modulo tramite un iniettore, ma prima dovresti avere un iniettore, e sembra che tu stia cercando di farla franca solo con uno.
    • Se avete bisogno di altri casi dall'iniettore si può sempre scrivere un'implementazione Provider con @Inject campi/metodi/costruttori, o anche prendere in parametri in un metodo @Provides (che sarà filled in with dependencies automatically).

Nel complesso ho ancora favorire l'approccio iniettore bambino (grazie per il link e il complimento per la mia risposta precedente!), Che si inserisce il vostro "attacchi dinamici basati su un'istanza iniettato" descrizione il migliore, e sarebbe letteralmente essere così semplice:

class PropertiesModule extends AbstractModule { 
    Properties properties; 

    PropertiesModule(Properties properties) { 
    this.properties = properties; 
    } 

    @Override public void configure() { 
    Names.bindProperties(binder(), properties); 
    } 
} 

Injector oldInjector = Guice.createInjector(allYourOtherModules); 
Module myModule = new PropertiesModule(oldInjector.get(Properties.class)); 
Injector injector = oldInjector.createChildInjector(myModule); 
+0

Un'altra buona risposta, grazie! Non sapevo del metodo Names.bindProperties(), dovrò salvarlo per quest'ultimo. Ho provato la soluzione che hai proposto la scorsa notte 2 e ha funzionato soprattutto, anche se non era così pulito che mi sarebbe piaciuto. Fondamentalmente sono arrivato alla conclusione che ciò che mi piacerebbe davvero fare non rientra nel design di Guice. Non possiedo il framework che sto implementando e non credo che gli iniettori possano essere disponibili in qualsiasi momento, quindi ho intenzione di rielaborare la nostra configurazione in un modo leggermente diverso. Grazie per la pronta risposta! –

Problemi correlati