[英]Dynamically injecting generic objects with guice
我想將以下類注入到我的應用程序中:
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
實例。
這里的主要問題是你不能在注入中使用注解的值。 還有一個問題涵蓋了這部分: Guice injection based on annotation value
您應該綁定提供者類,並通過注入 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 無論如何都需要知道“密鑰”,因此這在信息方面並沒有太大的變化。 缺點是 SomeClass API 現在得到一個工廠而不是具體的配置。
[編輯]
這里有人實際上確實使用自定義注入注入了帶注釋的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.