如何在需要注入实例的Guice中进行动态绑定? [英] How do you make dynamic bindings in Guice that require an injected Instance?

查看:634
本文介绍了如何在需要注入实例的Guice中进行动态绑定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'd like to create a Module that dynamically binds instances to named annotations. The use case is I would like to automatically bind the values in my configuration with the key in the properties file being the @Named value.

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

However the configuration is bound in a different module so I need the config to be injected. Solutions I've looked at are:


  1. 在configure()方法中绑定。
    这个方法不会被注入,我无法获得基本配置。

  1. Binding in the configure() method. This method is not injected into and I can not get the base configuration.

使用提供者/ @提供。
提供者只绑定单个实例。

Using a Provider/@Provides. Providers only bind a single instance.

使用MultiBinder。
我的用例与这个扩展名提供的有所不同。多绑定允许您单独绑定多个实例,然后将它们作为集合更为复杂的包含类型注入。我想分别绑定每个实例,并通过唯一的身份识别注入后者。

Using MultiBinder. My use case is a little different then what is provided by this extension. Multi-binding allows you to bind multiple instances separately and then have them injected as a Collection more complex containing type. I would like to bind each instance separately and have them by uniquely identifiable for injection latter.

使用childInjector。
不幸的是,如果没有对现有代码进行大量修改,这是不可能的。 a>是一个非常好的描述,如何解决这个问题这样的方式。

Use a childInjector. Unfortunately this isn't possible without some extensive modification of existing code. This answer is a very good description of how to solve this problem this way though.

注入粘合剂不知何故。 (我开始有点黑客)
Guice允许注入注射器以供后者使用,我尝试通过@Provides方法将Binder注入模块,然后直接使用binder来在方法中进行多个绑定。 Guice不会注入活页夹。

Inject the binder somehow. (I started getting a little hackier) Guice allows injecting the Injector for latter use, I tried injecting the Binder into the Module though a @Provides method and then using the binder directly to make multiple binds within the method. Guice would not inject the binder.


推荐答案

记住, 配置方法在注射器之前配置所有绑定的任何注入都可能发生。也就是说,一些东西:

Remember that all of the configure methods configure all of the bindings in an Injector before any injection can happen. That said, a few things:


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

  1. Binding @Named properties to the contents of a single Properties instance is so useful, there's a Names.bindProperties(...) method that does it automatically for you. The only trick is that you need to have the Properties instance at the time configure() is run.

如果它们都可以同时使用,不用担心在一个模块中绑定属性并将应用程序绑定到另一个模块中。只要他们都进入相同的注射器,Guice将结合它们,让他们满足彼此的依赖。

If they're all available at the same time, don't worry about binding the properties in one module and binding the application in another. As long as they all go into the same Injector, Guice will combine them all and let them satisfy each others' dependencies.

提供商可以返回不同的实例,通常可以 - 但是你是对的,它不会帮助您区分密钥。如果直接注入属性实例太丑了,请考虑使用轻量级的工厂:

Providers can return different instances, and usually do--but you're right that it won't help you differentiate between keys. If injecting the Properties instance directly is too ugly, consider making a lightweight factory instead:

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


  • 你不应该注入 Binder (或任何其他)到模块中。

  • You should never need to inject a Binder (or anything else) into a Module.


    • 如果您实现 Module binder 将是 configure()的参数。如果你按照你的要求扩展 AbstractModule ,只需调用 binder()方法。

    • 如果需要,您可以通过构造函数参数将依赖关系传递给模块,这是模块应该更改其创建的绑定的唯一方式。

    • 没有理由不能通过注射器创建模块,但您必须先注入一个注射器,这听起来像是试图摆脱只有一个。

    • 如果您需要注射器的其他实例,您可以随时使用 @Inject 字段/ 方法/构造函数,或者甚至在 @Provides 方法(这将是自动填写相关性)。

    • If you implement Module, the binder will be a parameter of configure(). If you extend AbstractModule as you should, just call the binder() method.
    • You can pass in dependencies through constructor arguments to the Module, if need be, which (as far as I'm concerned) is the only way Modules should vary the bindings they create.
    • There's no reason you couldn't create a Module through an Injector, but you'd have to have an Injector first, and it sounds like you're trying to get away with only having one.
    • If you need other instances from the Injector you can always write a Provider implementation with @Inject fields/methods/constructors, or even take in parameters in a @Provides method (which will be filled in with dependencies automatically).

    $ b总体而言,我仍然喜欢儿童注射器方法(感谢林k,并赞扬我以前的答案!),它适合您的动态绑定基于注入的实例描述是最好的,并将从字面上是这样简单:

    Overall I still favor the child injector approach (thanks for the link and compliment to my previous answer!), which fits your "dynamic bindings based on an injected instance" description the best, and would literally be this simple:

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

    这篇关于如何在需要注入实例的Guice中进行动态绑定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆