2016-06-12 15 views
1

Ich versuche derzeit, Injektion in einer Java-Konsole-Anwendung mit Guice implementieren. Die Anwendung importiert XML-Dateien in eine Datenbank. Jeder Importvorgang wird in einem AbstractImporter getan, was entweder ein UserImporter sein kann, ein ScheduleImporter usw.Guice benutzerdefinierten Bereich Eingabe und Beenden in der Java-Konsole Anwendung

public class ScheduleMigrator extends AbstractMigrator { 
    private final UserImporter userImporter; 
    private final ScheduleImporterFactory scheduleImporterFactory; 

    @Inject 
    public ScheduleMigrator(UserImporter userImporter, 
          ScheduleImporterFactory scheduleImporterFactory) { 
     this.userImporter = userImporter; 
     this.scheduleImporterFactory = scheduleImporterFactory; 
    } 

    public void migrate() { 
     // Migrate users 
     userImporter.run(); 

     // Migrate schedules for each type 
     for (ScheduleType scheduleTypes : ScheduleType.values()) { 
      ScheduleImporter importer = 
       scheduleImporterFactory.create(scheduleTypes); 
      importer.run(); 
     } 
    } 

} 

public class UserImporter extends AbstractImporter { 

    private final UserTransformer userTransformer; 
    private final ConfigurationService configurationService; 

    @Inject 
    public UserImporter(UserTransformer userTransformer, 
         ConfigurationService configurationService) { 
     this.userTransformer = userTransformer; 
     this.configurationService = configurationService; 
    } 

    public void run() { 
     // do stuff here 
    } 
} 

@Singleton 
public class UserTransformer { 
    // ...code ommited... 

} 

@ImporterScoped 
public class ConfigurationService { 
    // ...code ommited... 

} 

Ich habe erfolgreich meine eigenen Rahmen geschaffen (@ImporterScoped) für Klassen, die nur verfügbar sein sollten und instanziiert nur in einem Importer. Der Bereich wurde erstellt, indem die Schritte in the wiki ausgeführt wurden. Mein Problem ist, wie sollte ich den Bereich in ScheduleMigrator eingeben und verlassen? Wie Sie in ScheduleMigrator sehen können, wird jede Importer injiziert und ihre run() Methode aufgerufen. Es gibt auch Fabriken (basierend auf Guices @AssistedInject Funktion). Dies ist, wo ich möchte, dass jeder Bereich zu starten und zu beenden, sollten UserImporter und ScheduleImporterFactory in ihrem eigenen Bereich ausgeführt werden.

Dies ist eine grobe Vorstellung davon, was ich zu erreichen bin versucht:

importerScope.enter(); 
(new UserImporter()).run(); 
importerScope.exit(); 

Guice in der Dokumentation erwähnt die Verwendung von Abfangjäger, aber ich bin ein wenig verloren, wie kann es umgesetzt werden.

+0

Welche Scope-Implementierung verwenden Sie? Welcher Code löst einen Importeur aus? Was ist der Lebenszyklus eines Importeursobjekts? Guide AOP ist ein möglicher Weg, um dieses Problem zu lösen, aber ich denke, dass es in diesem Fall wahrscheinlich nicht notwendig ist. –

+0

Nicht sicher, ob ich richtig verstanden habe ... Ich benutze einen benutzerdefinierten Bereich implementiert durch Befolgen der Wiki-Leitfaden für benutzerdefinierte Bereiche. Ich habe meine ursprüngliche Frage aktualisiert, um Informationen darüber einzubeziehen, wie Importeure instanziiert und ausgeführt werden, hoffe, dass dies hilft! – giannoug

Antwort

1

Die Verwendung von AOP scheint ein sehr überentwickelter Ansatz zu sein und könnte zu Problemen führen. Wann gebe ich den Umfang ein? Wann verlasse ich? Was passiert, wenn ich zwei Importer Objekte instanziiere?

Stattdessen fügte ich eine runScoped Methode in , die eine Runnable dauert und führt es aus. Mit der Injektion bekomme ich den ImporterScope Umfang, gebe ihn ein und verlasse ihn entsprechend.

protected void runScoped(Runnable function) 
{ 
    scenarioScope.enter(); 

    try { 
     function.run(); 
    } 
    finally { 
     scenarioScope.exit(); 
    } 
} 

Verbrauch:

runScoped(() -> { 
    ScheduleImporter importer = 
      scheduleImporterFactory.create(scheduleTypes); 
    importer.run(); 
}); 

Dies führt zu einem Problem, wenn. In ScheduleMigrator kann ich nicht Importers injiziert werden, da ihre Instanziierung außerhalb eines Bereichs auftreten würde und Guice einen OutOfScopeException auslöst. Ich musste jede Importer in eine Provider wickeln.

private final Provider<UserImporter> userImporterProvider; 

runScoped(() -> { 
    UserImporter importer = userImporterProvider.get(); 
    importer.run(); 
}); 
+0

Ja, so war das, worauf ich in meinem Kommentar angespielt habe. Ich würde wahrscheinlich einen Guice MapBinder verwenden, um eine 'Map >' zu binden und diese in eine Dienstprogrammklasse einzufügen, die die 'runScoped()' Implementierung kapseln könnte. Dann würden Sie einfach 'runScoped (ImporterKind)' aufrufen und es würde den Bereich öffnen, 'get()' auf dem entsprechenden Provider aufrufen und 'run()' es und dann den Bereich schließen. Ist das sinnvoll? –

+0

Es macht Sinn! Ich bin neu in Guice (und Injektion im Allgemeinen), so habe ich eine schwierige Zeit zu verstehen, wie 'runScoped (ImporterKind)' könnte funktionieren – giannoug

+0

Ich stelle mir vor, dass 'ImporterKind' wäre eine enum, mit Werten wie' USER' "SCHEDULE", usw. - aber ich habe hier vielleicht kein gutes Verständnis für Ihren Problembereich. –