Guice:一个 "Provider<T>" 用于多个实现
Guice: One "Provider<T>" for multiple implementations
我有一个接口有 20 个左右的注释实现。如果我在编译时知道我需要哪个,我可以注入正确的,但我现在需要根据运行时参数动态注入一个。
根据我对文档的理解,我将不得不使用 20 次左右的 Provider<T>
注射,然后使用我需要的注射,这对我来说似乎太过分了。有没有办法让 inst(Provider<T>).get(MyAnnotation.class)
之类的东西绑定特定的实现,然后只将 Provider
注入我的 class?
注入一个MapBinder.
在您的模块中,将绑定加载到 MapBinder
,然后使您的运行时参数也可注入。此示例基于文档中的示例:
public class SnacksModule extends AbstractModule {
protected void configure() {
MapBinder<String, Snack> mapbinder
= MapBinder.newMapBinder(binder(), String.class, Snack.class);
mapbinder.addBinding("twix").to(Twix.class);
mapbinder.addBinding("snickers").to(Snickers.class);
mapbinder.addBinding("skittles").to(Skittles.class);
}
}
然后,在您的对象中,注入 Map
和参数。对于这个例子,我假设你已经为你的运行时参数绑定了一个 java.util.Properties
:
@Inject
public MyObject(Map<String, Provider<Snack>> snackProviderMap, Properties properties) {
String snackType = (String) properties.get("snackType");
Provider<Snack> = snackProviderMap.get(property);
// etc.
}
请注意,使用相同的 MapBinder
,您可以注入简单的 Map<String, Snack>
或 Map<String, Provider<Snack>>
; Guice 绑定两者。
如果您只想以编程方式获取实例,则可以注入 Injector。这很少是一个好主意——在可能的情况下注入 Provider<T>
是一个更好的主意,尤其是为了测试——但要反射性地获得绑定,这是唯一的方法。
class YourClass {
final YourDep yourDep; // this is the dep to get at runtime
@Inject YourClass(Injector injector) {
YourAnnotation annotation = deriveYourAnnotation();
// getProvider would work here too.
yourDep = injector.getInstance(Key.get(YourDep.class, annotation));
}
}
如果您尝试编写一个带有参数的 Provider,最好的表达方式是编写一个小型工厂。
class YourDepFactory {
@Inject @A Provider<YourDep> aProvider;
@Inject @B Provider<YourDep> bProvider;
// and so forth
Provider<YourDep> getProvider(YourParameter parameter) {
if (parameter.correspondsToA()) {
return aProvider;
} else if (parameter.correspondsToB()) {
return bProvider;
}
}
YourDep get(YourParameter parameter) {
return getProvider(parameter);
}
}
我有一个接口有 20 个左右的注释实现。如果我在编译时知道我需要哪个,我可以注入正确的,但我现在需要根据运行时参数动态注入一个。
根据我对文档的理解,我将不得不使用 20 次左右的 Provider<T>
注射,然后使用我需要的注射,这对我来说似乎太过分了。有没有办法让 inst(Provider<T>).get(MyAnnotation.class)
之类的东西绑定特定的实现,然后只将 Provider
注入我的 class?
注入一个MapBinder.
在您的模块中,将绑定加载到 MapBinder
,然后使您的运行时参数也可注入。此示例基于文档中的示例:
public class SnacksModule extends AbstractModule {
protected void configure() {
MapBinder<String, Snack> mapbinder
= MapBinder.newMapBinder(binder(), String.class, Snack.class);
mapbinder.addBinding("twix").to(Twix.class);
mapbinder.addBinding("snickers").to(Snickers.class);
mapbinder.addBinding("skittles").to(Skittles.class);
}
}
然后,在您的对象中,注入 Map
和参数。对于这个例子,我假设你已经为你的运行时参数绑定了一个 java.util.Properties
:
@Inject
public MyObject(Map<String, Provider<Snack>> snackProviderMap, Properties properties) {
String snackType = (String) properties.get("snackType");
Provider<Snack> = snackProviderMap.get(property);
// etc.
}
请注意,使用相同的 MapBinder
,您可以注入简单的 Map<String, Snack>
或 Map<String, Provider<Snack>>
; Guice 绑定两者。
如果您只想以编程方式获取实例,则可以注入 Injector。这很少是一个好主意——在可能的情况下注入 Provider<T>
是一个更好的主意,尤其是为了测试——但要反射性地获得绑定,这是唯一的方法。
class YourClass {
final YourDep yourDep; // this is the dep to get at runtime
@Inject YourClass(Injector injector) {
YourAnnotation annotation = deriveYourAnnotation();
// getProvider would work here too.
yourDep = injector.getInstance(Key.get(YourDep.class, annotation));
}
}
如果您尝试编写一个带有参数的 Provider,最好的表达方式是编写一个小型工厂。
class YourDepFactory {
@Inject @A Provider<YourDep> aProvider;
@Inject @B Provider<YourDep> bProvider;
// and so forth
Provider<YourDep> getProvider(YourParameter parameter) {
if (parameter.correspondsToA()) {
return aProvider;
} else if (parameter.correspondsToB()) {
return bProvider;
}
}
YourDep get(YourParameter parameter) {
return getProvider(parameter);
}
}