问题描述
我想创建一个动态绑定实例到命名注释的模块。用例是我想自动绑定配置中的值与属性文件中的键为@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:
-
在configure()方法中绑定。
此方法未注入,我无法获取基本配置。
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。
不幸的是,如果没有对现有代码进行大量修改,这是不可能的。 方法,它会自动为您。唯一的诀窍是你需要在运行 configure()
时运行 Properties
实例。
Binding
@Named
properties to the contents of a singleProperties
instance is so useful, there's aNames.bindProperties(...)
method that does it automatically for you. The only trick is that you need to have theProperties
instance at the timeconfigure()
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
, thebinder
will be a parameter ofconfigure()
. If you extendAbstractModule
as you should, just call thebinder()
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中创建需要注入实例的动态绑定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!