2016-06-12 3 views
1

В настоящее время я пытаюсь внедрить инъекцию в консольное приложение Java с помощью Guice. Приложение импортирует XML-файлы в базу данных. Каждая операция импорта выполняется в AbstractImporter, который может быть либо UserImporter, ScheduleImporter и т.д.Вход и выход Guice custom scope в приложении консоли Java

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... 

} 

Я успешно создал свой собственный объем (@ImporterScoped) для классов, которые должны быть доступны только и экземпляры только в Importer. Область была создана, выполнив следующие шаги: the wiki. Моя проблема в том, как мне войти и выйти из области в ScheduleMigrator?

Как вы можете видеть в ScheduleMigrator, вводится каждый Importer и вызывается его метод run(). Существуют также фабрики (основанные на функции Guice's @AssistedInject). Здесь я хочу, чтобы каждая область начала и конца, UserImporter и ScheduleImporterFactory должны работать в своем собственном объеме.

Это приблизительное представление о том, что я пытаюсь достичь:

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

документация Guice упоминает использование перехватчиков, но я немного потерял о том, как он может быть реализован.

+0

Какая реализация области применения вы используете? Какой код запускает импортер? Каков жизненный цикл объекта импортера? Руководство АОП является одним из возможных способов решения этой проблемы, но я думаю, что в этом случае, вероятно, это не обязательно. –

+0

Не уверен, правильно ли я понял ... Я использую настраиваемую область, реализованную, следуя руководству по вики на пользовательских областях. Я обновил свой первоначальный вопрос, чтобы включить информацию о том, как «Импортер получает экземпляр и запускается, надеюсь, что это поможет! – giannoug

ответ

1

Использование АОП представляется очень переработанным подходом и может вызвать проблемы. Когда я ввожу область? Когда я выйду? Что произойдет, если я создам два объекта Importer?

Вместо этого, я добавил runScoped метод в AbstractMigrator, который принимает Runnable и выполняет его. Используя инъекцию, я получаю область ImporterScope, введите и выйдите из нее соответствующим образом.

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

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

Использование:

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

Это вводит одну проблему, хотя. В ScheduleMigrator у меня не может быть введено Importers, потому что их инстанцирование произойдет за пределами области действия, а Guice выбрасывает OutOfScopeException. Мне пришлось обернуть каждый Importer в Provider.

private final Provider<UserImporter> userImporterProvider; 

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

Да, кое-что вроде этого было тем, о чем я упоминал в своем комментарии. Я бы, вероятно, использовал Guice MapBinder для привязки «Map >» и ввел это в класс утилиты, который мог бы инкапсулировать реализацию 'runScoped()'. Затем вы просто вызываете 'runScoped (ImporterKind)' и открываете область, вызываете 'get()' на соответствующем провайдере и 'run()' it, а затем закрываете область. Имеет ли это смысл? –

+0

Это имеет смысл! Я новичок в Guice (и инъекции в целом), поэтому мне сложно понять, как 'runScoped (ImporterKind)' может работать – giannoug

+0

Я представляю, что 'ImporterKind' будет перечислением, со значениями, такими как' USER' , 'SCHEDULE' и т. Д., Но я, возможно, не очень хорошо понимаю ваше проблемное пространство здесь. –

Смежные вопросы