如何使用自定义参数配置提供者?

How to configure providers with custom parameters?

我的 class 依赖于一些需要接受少量参数然后进行网络调用的服务,目前我正在传递这些参数,然后通过注入我的 class 的工厂创建这些服务。我需要将这些服务作为依赖注入,我知道我可以为它们创建提供者,但在大多数示例中,我看到提供者通常绑定到 serveraddres 等固定值,但我需要然后在 运行 时间内给出值。

下面是我的示例代码:

public SomeClass {
   private final SomeFactory someFactory;

   @Inject
   SomeClass(SomeFactory factory) {
      someFactory = factory;
   }

   public Foo getFoo(String fooId) {
      FooService fooService = someFactory.getFooService(fooId);
      return fooService.getFoo();
   }

}

我需要做的是:

public SomeClass {
   private final FooService fooService;

   @Inject
   SomeClass(FooService fooService) {
      this.fooService = fooService;
   }

   public Foo getFoo(String fooId) {
      return fooService.getFoo();
   }

}

更新 1

使用例更清晰:

  @Provides
  @RequestScoped
  public SomeService provideSomeService(Dep1 dep1, String code) throws IOException {
    return new SomeService.Builder()
        .withApplicationName("Foo")
        .setCode(code)  
        .build();
  }

这里,code可以默认为null,需要的时候我可以给它赋值。

我可以在提供程序创建之前以某种方式将参数传递给它吗?

如果您的值有绑定(这里,code 是一个没有绑定注释的字符串),那么您的更新 1 就是代码的样子。

在实践中,存在一些差异:

  • intString 值这样的常量通常使用绑定注释进行注释,@Named 或自定义注释。
  • 如果您需要在 Guice 初始化后向对象图中注入一个值,但对象图足够深,依赖注入仍然是一个好主意,您可以创建一个 child injector。通过这种方式,您可以使 @Named("code") String 在一个操作或对象中可访问,但不能在整个 Guice 应用程序中访问。
  • 如果 code 的值足够动态以至于无法通过 Guice 将其作为自己的键提供,那么您将不得不使用某种工厂传递它。对于基于 Builder 的对象,我会说您的 SomeFactory 实现是我在您的案例中想到的最好的实现。

如果您不需要使用 Builder,并且可以让 Guice 根据您的字段或构造函数参数创建对象,您可以代码生成一个 Factory。

  • Guice 可以通过 FactoryModuleBuilder 为您生成一个工厂,其功能称为 "assisted injection"
  • Google 的另一个工具,AutoFactory,将通过代码生成一个在 Guice 和 Dagger 中都有效的工厂实现。 (它被捆绑为 "Auto",其中包括一个名为 AutoValue 的模型对象生成器,它还生成注释实现。)

我在.

放了一个儿童注射器和辅助注射的小演示

此处最好的方法是参数化模块并将参数传递给您在运行时创建的提供程序:

public class MyModule extends AbstractModule {
  private final String code;

  public MyModule(String code) {
    this.code = code;
  }

  @Override public void configure() {
    Provider<Dep1> depProvider = getProvider(Dep1.class);
    bind(SomeService.class)
        .toProvider(() -> new SomeService.Builder()
            .withApplicationName("Foo")
            .withDep(depProvider.get())
            .setCode(code)  
            .build())
        .in(RequestScoped.class);
  }
}