我想将以下类注入我的应用程序:
public interface IConfigAccessor<T extends IConfig> {
...
}
ConfigAccessor
是在运行时动态创建的代理对象。这些对象的创建工作如下:
public class ConfigFactory implements IConfigFactory {
private final IConfigUpdater updater;
@Inject
public ConfigFactory(IConfigUpdater updater) {
this.updater = updater;
}
@Override
public <T extends IConfig> IConfigAccessor<T> register(final String configKey, final Class<T> configClass) {
ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);
updater.register(configCache);
return new ConfigAccessor<>(configCache, configKey, configClass);
}
}
如您所见,要创建这些对象,我需要注入ConfigUpdater
和其他依赖项。这意味着,需要完全配置guice。
要从Guice中获取实例,我使用以下代码:
IConfigFactory configClient = injector.getInstance(IConfigFactory.class);
IConfigAccessor<ConcreteConfig> accessor = configClient.register("key", ConcreteConfig.class)
目前,我可以获得所需的对象,但我必须在我的应用程序中手动传递它们。
相反,我想要的是以下内容:
public class SomeClass {
@Inject
public SomeClass(@Config(configKey="key") IConfigAccessor<ConcreteConfig> accessor) {
// hurray!
}
}
经过大量的研究,我对如何处理这个话题感到有点迷茫。 Guice提供了许多不同的功能,包括简单的Providers
,自定义Listeners
,可以扫描类并识别自定义注释,FactoryModuleBuilders
等等。
我的问题非常具体,我不确定使用哪些内容以及如何使其正常运行。我甚至不确定Guice是否可以做到这一点?
我想在构造函数参数中使用以下注释:
@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectConfig {
String configKey();
}
在模块内部,我可以将提供者绑定到IConfigAccessor(带有上述注释),如下所示:
bind(IConfigAccessor.class).annotatedWith(InjectConfig.class)
.toProvider(new ConfigProvider<>());
然而,这有两个问题:
IConfigAccessor
。要创建这样的实例,提供者需要IConfigUpdater
,但由于我使用'new'作为提供者,我无法注入它。configKey
。第二种方法:
假设我已经知道我想在启动期间注入的所有配置和configKeys。在这种情况下,我可以遍历所有可能的configKeys并具有以下绑定:
String configKey = "some key";
final Class<? extends IConfig> configClass =...;
bind(IConfigAccessor.class).annotatedWith(Names.named(configKey))
.toProvider(new ConfigProvider<>(configKey, configClass));
然而,问题(1)仍然存在:提供者无法获得IConfigUpdater
实例。
答案 0 :(得分:1)
这里的主要问题是你不能在注射中使用注释的值。还有另一个问题涉及这一部分: Guice inject based on annotation value
您应该绑定提供程序类,而不是绑定提供程序实例,并按injecting a typeliteral获取该类。
这样,您的配置工厂可能看起来像这样:
public class ConfigFactory<T extends IConfig> implements IConfigFactory {
@Inject private final IConfigUpdater updater;
@Inject private TypeLiteral<T> type;
@Override
public IConfigAccessor<T> register(final String configKey) {
Class<T> configClass = (Class<T>)type.getRawType();
ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);
updater.register(configCache);
return new ConfigAccessor<>(configCache, configKey, configClass);
}
}
然后是SomeClass:
public class SomeClass {
@Inject
public SomeClass(ConfigFactory<ConcreteConfig> accessor) {
ConcreteConfig config = accessor.register("key");
}
}
因为SomeClass需要知道&#34; key&#34;无论如何,这不是一个信息变化太多的变化。缺点是SomeClass API现在获得工厂而不是具体的配置。
[编辑]
here实际上是使用自定义注入注入注释值的人。