2012-11-06 15 views
9

Chciałbym utworzyć moduł, który dynamicznie łączy instancje z nazwanymi adnotacjami. Przypadek użycia jest taki, że chciałbym automatycznie powiązać wartości w mojej konfiguracji z kluczem w pliku właściwości będącym wartością @Named.Jak utworzyć dynamiczne powiązania w Guice, które wymagają iniekcji iniekcji?

Jednak konfiguracja jest powiązana z innym modułem, więc potrzebuję wtrysku do konfiguracji. Rozwiązania, na które patrzę, to:

  1. Powiązanie w metodzie configure(). Ta metoda nie jest wprowadzana i nie mogę uzyskać konfiguracji podstawowej.

  2. Korzystanie z dostawcy/@ Zapewnia. Dostawcy wiążą tylko jedno wystąpienie.

  3. Korzystanie z MultiBlacza. Mój przypadek użycia jest trochę inny niż to, co zapewnia to rozszerzenie. Multi-binding pozwala na powiązanie wielu instancji osobno, a następnie wprowadzenie ich jako kolekcji bardziej złożonej zawierającej typ. Chciałbym związać każdą instancję osobno i mieć je jednoznacznie identyfikowalne dla wtrysku.

  4. Użyj childInjector. Niestety nie jest to możliwe bez jakiejś szerokiej modyfikacji istniejącego kodu. This answer jest bardzo dobrym opisem sposobu rozwiązania tego problemu w ten sposób.

  5. W jakiś sposób wstrzyknij spinacz. (Zacząłem robić się trochę bardziej niepewny) Guice pozwala na wstrzyknięcie wtryskiwacza do drugiego zastosowania, próbowałem wstrzyknąć spoiwo do modułu metodą @Provides, a następnie użyć spoiwa bezpośrednio, aby wykonać wiele wiązań w ramach metody. Guice nie wstrzyknęłaby spoiwa.

Odpowiedz

8

Pamiętaj, że wszystko metod configure skonfigurować wszystko z wiązaniami w sposób Injector przed dowolny wtrysk może się zdarzyć. Powiedział, że kilka rzeczy:

  1. Oprawa @Named właściwości do treści pojedynczego Properties przykład jest tak przydatny, tam Names.bindProperties(...) metoda, która robi to automatycznie. Jedyną sztuczką jest konieczność uruchomienia instancji Properties w momencie uruchomienia configure().

    Jeśli wszystkie są dostępne w tym samym czasie, nie martw się o powiązanie właściwości w jednym module i powiązanie aplikacji z innym. Tak długo, jak wszyscy idą do tego samego Injector, Guice połączy je wszystkie i pozwoli zaspokoić wzajemne zależności.

  2. Dostawcy mogą zwracać różne instancje i zazwyczaj robią to - ale masz rację, że nie pomogą Ci w rozróżnieniu kluczy. Jeśli wstrzyknięcie instancję Właściwości bezpośrednio jest zbyt brzydki, zastanów się lekką fabryki zamiast:

    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. Nigdy nie należy trzeba wstrzyknąć Binder (lub czegokolwiek innego) do modułu.

    • W przypadku zastosowania Module The binder będzie parametrem configure(). Jeśli rozszerzysz AbstractModule tak, jak powinieneś, po prostu wywołaj metodę binder().
    • Możesz przekazywać zależności za pomocą argumentów konstruktora do Modułu, w razie potrzeby, który (o ile mi chodzi) jest jedynym sposobem, w jaki Moduły powinny zmieniać powiązania, które tworzą.
    • Nie ma powodu, dla którego nie można stworzyć modułu za pomocą wtryskiwacza, ale najpierw trzeba mieć wtryskiwacz i wygląda na to, że próbujesz uciec tylko mając jeden.
    • Jeśli potrzebujesz innych instancji z Injector, zawsze możesz napisać implementację Provider za pomocą pól/metod/konstruktorów @Inject, a nawet zastosować parametry w metodzie @Provides (która będzie filled in with dependencies automatically).

Ogólnie nadal sprzyjać podejście wtryskiwacza dzieckiem (dzięki za link i komplement do mojej poprzedniej odpowiedzi!), Która pasuje do „Dynamic powiązań opartych na wtryskiwanego przykład” opis najlepszych i dosłownie być tak proste:

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

Kolejna dobra odpowiedź, dzięki! Nie wiedziałem o metodzie Names.bindProperties(), będę musiał to zapisać na później. Wypróbowałem rozwiązanie, które zaproponowałeś w zeszłej nocy 2 i to w większości zadziałało, chociaż nie było tak czyste, to bym mu się spodobał. Zasadniczo doszedłem do wniosku, że to, co chciałbym robić, nie należy do projektu Guice. Nie jestem właścicielem frameworka, w którym wdrażam i nie wierzę, że wtryskiwacze dla dzieci będą dostępne w najbliższym czasie, więc zamierzam przerobić naszą konfigurację nieco inaczej. Dziękuję za szybką odpowiedź! –

Powiązane problemy