2012-11-06 33 views
9

我想创建一个动态绑定实例到命名注释的模块。用例是我想自动将配置中的值与作为@Named值的属性文件中的键绑定。如何在需要注入实例的Guice中进行动态绑定?

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

  1. 在configure()方法中进行绑定。 这种方法没有注入,我无法获得基本配置。

  2. 使用提供程序/ @提供。 提供者仅绑定一个实例。

  3. 使用MultiBinder。 我的用例与本扩展提供的有些不同。多重绑定允许您分别绑定多个实例,然后将它们作为Collection更复杂的包含类型注入。我想单独绑定每个实例,并通过唯一标识后者进行注入。

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

  5. 以某种方式注入活页夹。 (我开始变得有点冒险) Guice允许注入注射器以供后期使用,我尝试通过@Provides方法将Binder注入模块,然后直接使用粘合剂在该方法内进行多重绑定。 Guice不会注入粘合剂。

回答

8

记住所有的configure方法Injector注射前的任何可能发生配置绑定的所有。这就是说,几件事情:

  1. 绑定@Named性质单一Properties实例的内容是非常有用,有一个Names.bindProperties(...)方法自动为您完成。唯一的窍门是,您需要在configure()运行时有Properties实例。

    如果它们全都可用,则不必担心绑定一个模块中的属性并将应用程序绑定到另一个模块中。只要他们都进入相同的Injector,吉斯将他们全部结合起来,让他们满足彼此的依赖。

  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(或其他东西)到模块。

    • 如果实现Module,该binder将是configure()的参数。如果扩展AbstractModule,你应该,只需调用binder()方法。
    • 您可以通过依赖构造函数参数的模块通过,如果需要的话,它(就我而言)是唯一的出路模块应该改变他们所创造的绑定。
    • 没有理由你无法通过喷油器创建一个模块,但你必须先有一个喷油器,这听起来像你想用只有一脱身。
    • 如果您需要注入器的其他实例,您总是可以使用@Inject字段/方法/构造函数编写Provider实现,甚至可以使用@Provides方法(将为filled in with dependencies automatically)写入参数。

总的来说,我还是赞成孩子注射的方法(感谢您的链接,并称赞我以前的答案!),它适合您“的基础上注入的情况下动态绑定”介绍最好的,而且会从字面上这么简单:

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); 
+0

另外一个很好的答案,谢谢!我不知道Names.bindProperties()方法,我必须为后者保存。我尝试了你昨晚在2号提出的解决方案,它大部分工作,虽然并不像我本来喜欢的那样干净。我基本上得出的结论是,我真正想做的事情不属于Guice的设计。我没有,我在部署框架,我不相信孩子注射器将可用特征很快,所以我会有点不同返工我们的配置。尽管谢谢你的及时答复! –

相关问题