Java 控制台应用程序中的 Guice 自定义范围进入和退出

Guice custom scope entry and exit in Java console application

我目前正在尝试使用 Guice 在 Java 控制台应用程序中实施注入。该应用程序在数据库中导入 XML 个文件。每个导入操作都在 AbstractImporter 中完成,可以是 UserImporterScheduleImporter

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 的 @AssistedInject 特性)。这是我希望每个范围开始和结束的地方,UserImporterScheduleImporterFactory 应该 运行 在他们自己的范围内。

这是我要实现的目标的粗略想法:

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

Guice 的文档提到了拦截器的使用,但我对如何实现它有点迷茫。

使用 AOP 似乎是一种过度设计的方法,可能会引入问题。我什么时候进入范围?我什么时候退出?如果我实例化两个 Importer 对象会怎样?

相反,我在 AbstractMigrator 中添加了一个 runScoped 方法,该方法接受 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();
});