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

时间:2016-03-15 05:39:25

标签: java guice

我的类依赖于一些需要接受少量参数然后进行网络调用的服务,目前我正在传递这些参数,然后通过注入我的类的工厂创建这些服务。我需要将这些服务作为依赖项注入,我知道我可以为它们创建提供程序,但在大多数示例中,我看到提供程序通常绑定到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,如果需要,我可以在其中提供一些价值。

我可以以某种方式在创建提供者之前将其传递给提供者吗?

2 个答案:

答案 0 :(得分:1)

如果你有一个绑定值(这里,code是一个没有绑定注释的String),那么你的Update 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的模型对象生成器,它也生成注释实现。)

我在my other SO answer here中进行了儿童注射器和辅助注射的小型演示。

答案 1 :(得分:0)

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

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);
  }
}