2017-11-07 2 views
0

Ich bin relativ neu zu Guice, und einige Dinge immer noch eine ziemlich harte Zeit. Meine besondere Frage ist, wie gehen Sie mit verschachtelten Injektionen in Guice. Beispiel:Verwenden Guice verschachtelte injects

Klasse A verwendet Klasse B über @Inject und der Klasse B verwendet Klasse C.

Explizit:

Mein Modul, wo ich Provider binden.

public class ModuleBinder extends AbstractModule { 

    @Override 
    protected void configure() { 
     bind(DatabaseControllerInterface.class) 
     .toProvider(DatabaseControllerProvider.class).asEagerSingleton(); 

     bind(AnalyzerInterface.class) 
     .toProvider(AnalyzerProvider.class).asEagerSingleton(); 

     bind(SystemAdministrationInterface.class) 
     .toProvider(SystemAdministrationProvider.class).asEagerSingleton(); 

     bind(LogInServiceInterface.class) 
     .toProvider(LogInServiceProvider.class); 
    } 
} 

Die DatabaseControllerProvider:

public class DatabaseControllerProvider implements Provider<DatabaseControllerInterface> { 

    @Override 
    public DatabaseControllerInterface get() { 
     return new DatabaseControllerImpl(); 
    } 
} 

Die LogInServiceProvider:

public class LogInServiceProvider implements Provider<LogInServiceInterface> { 

    @Override 
    public LogInServiceInterface get() { 
     return new LogInServiceImpl(); 
    } 
} 

Und schließlich die LogInService verwendet:

public class LogInServiceImpl implements LogInServiceInterface{ 

    @Inject 
    private DatabaseControllerProvider databaseControllerProvider; 

    private final DatabaseControllerInterface databaseController; 


    public LogInServiceImpl() { 
     this.databaseController = databaseControllerProvider.get(); 
    } 

    @Override 
    public User register(final String mail, final String userName, final String password) { 
     databaseController.registerUser(userName, mail, password, UserRole.ADMIN); 
    } 

} 

Der Aufruf lautet dann:

Ich weiß, die meisten von euch werden mit diesem Code krank werden, aber hey, ich bin ein Anfänger mit Guice, also bitte sei sanft mit mir.

Ich möchte Constructor-Injektion verwenden, erkannte ich bereits, dass Feldinjektion als "böse" gilt. Haben Sie eine Idee, wie Sie das schaffen, indem Sie die Anbieter behalten (ich brauche sie)?

Mit den Injektionen im Beispiel wird auf der "zweiten" Ebene nichts ausgeführt, die DatabaseControllerImpl in LogInServiceImpl ist null.

Habe ich etwas falsch konfiguriert? Habe ich die Verwendung von Angeboten und/oder Modulen missverstanden?

Ich hoffe jemand kann und will mir helfen. Wenn Sie weitere Informationen benötigen, schreiben Sie einen Kommentar.

Mit freundlichen Grüßen

JosefRucksack

Antwort

0

Ihre direkte Antwort: Sie new T(); in Ihrem Provider anrufen, die nicht Feldeinkopplung unterstützt.

Erstens, ein echter Zeitsaver: Behalten Sie nicht Ihre expliziten Provider. Wenn Sie eine T gebunden haben, erlaubt Ihnen Guice, eine Provider zu injizieren oder Injector.getProvider für diese T anzurufen, auch wenn Sie nicht explizit einen Provider selbst erstellt haben.Siehe die Built-In Bindings Seite auf dem Wiki, oder Injector docs (Hervorhebung von mir):

mehrere Standardbindungen enthält:

  • Diese Injector Instanz selbst
  • A Provider<T> für jede Bindung von Typ T
  • Der Logger für die einzuspeisende Klasse
  • Die Bühne, in dem der Injektor

Stattdessen erstellt wurde, es zu tun auf diese Weise:

public class ModuleBinder extends AbstractModule { 

    @Override 
    protected void configure() { 
     bind(DatabaseControllerInterface.class) 
      .to(DatabaseControllerImpl.class).asEagerSingleton(); 
     bind(AnalyzerInterface.class) 
      .to(AnalyzerImpl.class).asEagerSingleton(); 
     bind(SystemAdministrationInterface.class) 
      .to(SystemAdministrationImpl.class).asEagerSingleton(); 
     bind(LogInServiceInterface.class) 
      .to(LogInServiceImpl.class); 
    } 
} 

Sie dann die gleiche Wahl, die Sie jetzt tun müssen, T oder Provider<T> zu injizieren und rufen getInstance oder getProvider nach Bedarf.


Wenn Ihr Provider unbedingt notwendig ist, vor allem, wenn sie tatsächlich eine Instanz von einem anderen System oder Service Locator erhalten, eine andere Option ist, Ihre @Inject Felder in sie wie in den Provider bindings wiki page hinzufügen und gibt sie in Ihr Konstruktor, oder nur inject a MembersInjector<T>:

public class LogInServiceProvider implements Provider<LogInServiceInterface> { 
    @Inject MembersInjector<LogInServiceImpl> logInServiceImplInjector; 

    @Override 
    public LogInServiceInterface get() { 
     LogInServiceImpl logInServiceImpl = YourExternalDep.getLogInService(); 
     logInServiceImplInjector.injectMembers(logInServiceImpl); 
     return logInServiceImpl; 
    } 
} 

Doch diese expliziten-Provider-Lösung ist Guice nicht idiomatisches und nur mit externem oder Legacy-Code verwendet werden soll. Der ganze Existenzgrund von Guice ist es, den Textbaustein zu automatisieren und Ihre Systeme klar und flexibel zusammenzuführen. Anbieter sind ein Implementierungsdetail; lass Guice sie für dich erschaffen.

+0

Vielen Dank! Das hat mir wirklich geholfen! Ich denke, es funktioniert auch mit Guices JPA Persistence Provider, habe ich recht? Wirklich vertieft mein Verständnis von Guice! – JosefRucksack

+0

@JosefRucksack Schön zu helfen! Ich habe leider keine Gelegenheit, JPA zu verwenden, daher bin ich mir nicht sicher, aber ich sehe nichts [in den Dokumenten] (https://github.com/google/guice/wiki/JPA) das verweist darauf, explizite Anbieter von Guice-Objekten zu benötigen. –