使用 Guice 嵌套注入

Use Guice nested injects

我对 Guice 比较陌生,有些事情仍然让我很难过。 我的具体问题是,您如何处理 Guice 中的嵌套注入。 示例:

Class A 通过 @Inject 使用 Class B,Class B 使用 Class C.

明确:

我绑定到提供商的模块。

public class ModuleBinder extends AbstractModule {

    @Override
    protected void configure() {
        bind(DatabaseControllerInterface.class)
        .toProvider(DatabaseControllerProvider.class).asEagerSingleton();

        bind(AnalyzerInterface.class)
        .toProvider(AnalyzerProvider.class).asEagerSingleton();

        bind(SystemAdministrationInterface.class)
        .toProvider(SystemAdministrationProvider.class).asEagerSingleton();

        bind(LogInServiceInterface.class)
        .toProvider(LogInServiceProvider.class);
    }
}

DatabaseControllerProvider:

public class DatabaseControllerProvider implements Provider<DatabaseControllerInterface> {

    @Override
    public DatabaseControllerInterface get() {
        return new DatabaseControllerImpl();
    }
}

LogInServiceProvider:

public class LogInServiceProvider implements Provider<LogInServiceInterface> {

    @Override
    public LogInServiceInterface get() {
        return new LogInServiceImpl();
    }
}

最后,LogInService 使用:

public class LogInServiceImpl implements LogInServiceInterface{

    @Inject
    private DatabaseControllerProvider databaseControllerProvider;

    private final DatabaseControllerInterface databaseController;


    public LogInServiceImpl() {
         this.databaseController = databaseControllerProvider.get();
    }

    @Override
    public User register(final String mail, final String userName, final String password) {
        databaseController.registerUser(userName, mail, password, UserRole.ADMIN);
    }

}

那么电话是:

public class Test() {
     public static test() {
         final Injector injector = Guice.createInjector(new ModuleBinder());
         logInService = injector.getInstance(LogInServiceInterface.class);
         logInService.registerUser("test", "test", "test");
      }
}

我知道你们中的大多数人都会厌倦那些代码,但是嘿,我是 Guice 的初学者,所以请对我温柔一些。

我想使用构造函数注入,我已经意识到可以考虑字段注入"evil"。您知道如何通过保留提供者(我需要他们)来实现它吗?

使用示例中的注入在 "second" 级别上没有任何作用,LogInServiceImpl 中的 DatabaseControllerImplnull

我是不是配置有误?我是否误解了 Provides and/or 模块的用法?

我希望有人能够并且愿意帮助我。如果您需要更多信息,post 评论。

谨致问候,

约瑟夫背囊

您的直接回答:您在不支持字段注入的提供程序中调用 new T();

首先,一个真正节省时间的方法:不要保留您的显式提供程序。如果你绑定了一个 T,Guice 允许你为那个 T 注入一个 Provider 或调用 Injector.getProvider,即使你自己没有明确创建一个 Provider。请参阅维基上的 Built-In Bindings 页面, 或 Injector docs(强调我的):

Contains several default bindings:

  • This Injector instance itself
  • A Provider<T> for each binding of type T
  • The Logger for the class being injected
  • The Stage in which the Injector was created

相反,这样做:

public class ModuleBinder extends AbstractModule {

    @Override
    protected void configure() {
        bind(DatabaseControllerInterface.class)
            .to(DatabaseControllerImpl.class).asEagerSingleton();
        bind(AnalyzerInterface.class)
            .to(AnalyzerImpl.class).asEagerSingleton();
        bind(SystemAdministrationInterface.class)
            .to(SystemAdministrationImpl.class).asEagerSingleton();
        bind(LogInServiceInterface.class)
            .to(LogInServiceImpl.class);
    }
}

然后您可以像现在一样选择,注入 TProvider<T> 并根据需要调用 getInstancegetProvider


如果您的供应商绝对必要,特别是如果他们实际上从其他系统或服务定位器接收实例,另一种选择是添加您的 @Inject 字段像在 Provider bindings wiki page and pass them into your constructor, or to just inject a MembersInjector<T>:

中那样进入它们
public class LogInServiceProvider implements Provider<LogInServiceInterface> {
    @Inject MembersInjector<LogInServiceImpl> logInServiceImplInjector;

    @Override
    public LogInServiceInterface get() {
        LogInServiceImpl logInServiceImpl = YourExternalDep.getLogInService();
        logInServiceImplInjector.injectMembers(logInServiceImpl);
        return logInServiceImpl;
    }
}

但是,这种显式提供程序解决方案不是惯用的 Guice,只能与外部或遗留代码一起使用。 Guice 存在的全部原因是自动化样板文件,让您的系统清晰灵活地组合在一起。提供者是一个实现细节;让 Guice 为您创建它们。