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

查看:725
本文介绍了如何在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。
我的用例是有点不同,然后这个扩展提供了什么。多重绑定允许您单独绑定多个实例,然后将它们作为Collection更复杂的包含类型注入。

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。
不幸的是,如果没有对现有代码进行大量修改,这是不可能的。 此答案

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.

以某种方式注入binder。 (我开始得到一点点hackier)
Guice允许注入后来使用的Injector,我尝试通过一个@Provides方法注入Binder到模块,然后使用绑定器直接在该方法中进行多个绑定。

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.


推荐答案

configure 方法配置注入器中的所有绑定可能会发生任何 注入。也就是说,一些事情:

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 属性单个 Properties 实例的内容非常有用,因此有一个 Names.bindProperties(...) 方法,它会自动为您。唯一的诀窍是你需要在运行 configure()时运行 Properties 实例。

  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.

如果它们同时可用,则不必担心在一个模块中绑定属性,而在另一个模块中绑定应用程序。只要他们都进入相同的 Injector ,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.

提供者可以返回不同的实例,通常会做到 - 但你是对的,它不会帮助你区分键。如果直接注入Properties实例太丑陋,可以考虑使用一个轻量级工厂:

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


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


    • 如果实现 Module binder 将是 configure()的参数。如果你应该扩展 AbstractModule ,只需调用 binder()方法。

    • 您可以通过构造函数参数将依赖传递给模块,如果需要的话,就我而言,这是模块应该改变他们创建的绑定的唯一方式。

    • 没有理由你不能通过喷油器创建一个模块,但你必须先有一个喷油器,它听起来像你想逃避只有一个。

    • 如果您需要Injector的其他实例,您可以随时使用 @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).

    总体来说,我仍然喜欢child injector方法(感谢链接和恭维我的以前的答案!),它适合你的动态绑定基于注入的实例描述最好的,这是简单的:

    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天全站免登陆