如何在Guice中进行需要注入实例的动态绑定?

时间:2012-11-06 01:08:07

标签: java dynamic configuration guice

我想创建一个动态地将实例绑定到命名注释的模块。用例是我想自动绑定配置中的值,属性文件中的键是@Named值。

但是配置绑定在不同的模块中,所以我需要注入配置。我看过的解决方案是:

  1. 在configure()方法中绑定。 此方法未注入,我无法获得基本配置。

  2. 使用Provider / @ Provide。 提供者只绑定一个实例。

  3. 使用MultiBinder。 我的用例与此扩展提供的内容略有不同。多重绑定允许您单独绑定多个实例,然后将它们作为包含更复杂类型的集合注入。我想分别绑定每个实例,并通过唯一可识别的方式将它们注入后者。

  4. 使用childInjector。 不幸的是,如果不对现有代码进行大量修改,这是不可能的This answer是如何以这种方式解决这个问题的非常好的描述。

  5. 以某种方式注入活页夹。 (我开始有点hackier) Guice允许注入Injector供以后使用,我尝试通过@Provides方法将Binder注入模块,然后直接使用binder在方法中进行多次绑定。 Guice不会注入活页夹。

1 个答案:

答案 0 :(得分:9)

请记住{em>所有 configure方法在任何注入之前Injector中配置所有绑定可以发生。那说了几件事:

  1. @Named属性绑定到单个Properties实例的内容非常有用,有一个Names.bindProperties(...)方法可以自动为您执行此操作。唯一的诀窍是,您需要在Properties运行时拥有configure()实例。

    如果它们同时可用,请不要担心在一个模块中绑定属性并将应用程序绑定到另一个模块中。只要它们都进入相同的Injector,Guice就会将它们组合在一起,让它们满足彼此的依赖关系。

  2. 提供商可以返回不同的实例,通常会这样做 - 但你说得对,它无法帮助你区分密钥。如果直接注入Properties实例太难看了,请考虑改为使用轻量级工厂:

    public class ConfigOracle {
      @Inject private Properties properties;
    
      public String getAsString(String key) { ... }
      public int getAsInt(String key) { ... }
    }
    
    public class SomeConfigUser {
      @Inject private ConfigOracle configOracle;
    
      public void doStuff() {
        doStuffBasedOn(configOracle.getAsString("my.properties.key"));
      }
    }
    
  3. 您永远不需要将Binder(或其他任何内容)注入模块。

    • 如果您实施Modulebinder将是configure()的参数。如果您应该延长AbstractModule,请调用binder()方法。
    • 你可以通过构造函数参数将依赖关系传递给Module,如果需要的话,(就我而言)是Module应该改变他们创建的绑定的唯一方法。
    • 没有理由你不能通过注射器创建一个模块,但是你必须首先注射一个注射器,这听起来好像你只想拥有一个注射器。
    • 如果您需要Injector中的其他实例,您始终可以使用Provider字段/方法/构造函数编写@Inject实现,甚至可以使用@Provides方法接收参数(这将是是filled in with dependencies automatically)。
  4. 总的来说,我仍然倾向于使用子注入器方法(感谢链接并赞美我以前的答案!),这适合您的“基于注入实例的动态绑定”描述最好,并且字面意思就是这么简单:

    class PropertiesModule extends AbstractModule {
      Properties properties;
    
      PropertiesModule(Properties properties) {
        this.properties = properties;
      }
    
      @Override public void configure() {
        Names.bindProperties(binder(), properties);
      }
    }
    
    Injector oldInjector = Guice.createInjector(allYourOtherModules);
    Module myModule = new PropertiesModule(oldInjector.get(Properties.class));
    Injector injector = oldInjector.createChildInjector(myModule);