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

时间:2016-06-12 14:51:04

标签: java dependency-injection guice interceptor

我目前正在尝试使用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的文档提到了拦截器的使用,但我对如何实现拦截器感到有点迷失。

1 个答案:

答案 0 :(得分:1)

使用AOP似乎是一种非常过度设计的方法,可能会引入问题。我什么时候进入范围?我什么时候退出?如果我实例化两个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();
});