2016-08-09 115 views
2

Inject Ich denke Guice für DI in meiner App zu verwenden, wo ich in der Lage sein sollte, die Implementierungen zur Laufzeit zu tauschen. Ein Beispiel unten vorgesehen ist, um die Anforderung zu veranschaulichen:Inject Abhängigkeiten zur Laufzeit mit Google Guice

class ValidationEngine { 
    public void validate(ValidationService vs) {} 
} 

class Client1_ValidationService implements ValidationService {} 
class Client2_ValidationService implements ValidationService {} 

Einer der obigen Implementierung sollte, sagen basierend auf Client-Namen bestätigen Funktion zur Laufzeit gebunden werden Client1 oder Client2

Ich dachte, die ValidationEngine ändern wie das:

Das Problem mit dem obigen Ansatz besteht darin, dass der Parameter für die Annotation @Named statisch ist; Tatsächlich akzeptieren Annotationen keine Laufzeitwerte. Gibt es in Guice andere Ansätze, um diese Art von Problemen zu lösen?

Antwort

0

können Sie versuchen, Injector.createChildInjector zu benutzen, um Ihre eigenen Injektor für jede ValidationService Implementierung zu erstellen:

Injector client1Injector = injector.createChildInjector(new Module() { 
    @Override 
    public void configure(final Binder binder) { 
     binder 
      .bind(ValidationService.class) 
      .to(Client1_ValidationService.class); 
     } 
    }); 

ValidationEngine client1Engine = 
    client1Injector.getInstance(ValidationEngine.class) 

Aber das bedeutet, dass Sie alle Kind-Injektoren irgendwie zu verwalten haben.

+0

Dies scheint in Ordnung zu sein. Nur um die Dinge zu klären - wenn ich also 5 Kunden habe, werde ich mit 5 Injektoren enden. Und das Speichern in HashMap kann dazu beitragen, dass die Injektoren die Client-ID verwenden. Ist das ein richtiger Ansatz? –

+0

@giri_col Scheint so. Sie müssen den Injektor für jede 'ValidationService'-Implementierung beibehalten. So etwas - https://gist.github.com/KetothXupack/b4f6786a1590c7a2466be5f9523a564a – vsminkov

1

Sie können Konfigurationsinformationen einfach über den Konstruktor an Ihr Guice-Modul übergeben.

Pseudocode:

main() { // your main method 
    flags = parseFlags() 
    injector = guice.createInjector(new MyModule(flags.validator)) 
} 

MyModule { // your guice module 
    constructor(validator): this.validator = validator; 
    configure() { 
     Class<ValidatorService> client_validator; 
     if this.validator == KNOWN_CLIENT1: 
      client_validator = Client1_ValidationService.class 
     else: 
      client_validator = Client2_ValidationService.class 
     bind(ValidationService.class).to(client_validator); 
    } 
} 

Guice gegen diese Vorsichtsmaßregeln, da sie die Oberfläche für Sie erhöht zu testen. https://github.com/google/guice/wiki/AvoidConditionalLogicInModules

0

1) Injizieren direkt Injektor mit Namen, wie:

@Inject 
private Injector injector; 

public ValidationService getValidationServiceForClient(String clientName) { 
    return injector.getInstance(Key.get(ValidationService.class, Names.named(clientName))); 
} 

2) auch anders:

public class ValidationServiceProviderImpl implements ValidationServiceProvider { 

    @Inject 
    @Named("ClientA") 
    private ValidationService clientAValidationService; 

    @Inject 
    @Named("ClientB") 
    private ValidationService clientBValidationService; 

    public ValidationService getValidationServiceForClient(String clientName) { 
     switch (clientName) { 
      case "ClientA": return clientAValidationService; 
      case "ClientB": return clientBValidationService; 
     } 
     return null; // return default validationService for any other client 
    } 
} 

public interface ValidationServiceProvider { 
    ValidationService getValidationServiceForClient(String clientName); 
} 

Konfiguration:

Injector injector = Guice.createInjector(new AbstractModule() { 
    protected void configure() { 
     bind(ValidationService.class) 
      .annotatedWith(Names.named("ClientA")) 
      .to(ClientA_ValidationService.class); 
     bind(ValidationService.class) 
      .annotatedWith(Names.named("ClientB")) 
      .to(ClientB_ValidationService.class); 
     bind(ValidationServiceProvider.class) 
      .to(ValidationServiceProviderImpl.class); 
    } 
}); 

Beispiel unter Verwendung provider:

ValidationServiceProvider validationServiceFactory = 
    injector.getInstance(ValidationServiceProvider.class); 
ValidationService clientA = 
    validationServiceFactory.getValidationServiceForClient("ClientA"); 
ValidationService clientB = 
    validationServiceFactory.getValidationServiceForClient("ClientB"); 

Beispiel mit Injektor direkt:

ValidationService clientA = 
    injector.getInstance(Key.get(ValidationService.class, Names.named("ClientA"))); 
ValidationService clientB = 
    injector.getInstance(Key.get(ValidationService.class, Names.named("ClientB")));