Guice:One&#34; Provider <t>&#34;用于多种实现

时间:2015-05-08 21:42:44

标签: java dependency-injection inversion-of-control guice

我的界面有20个左右的带注释的实现。如果我知道在编译时需要哪个,我可以注入正确的,但我现在需要根据运行时参数动态注入一个。

正如我对文档的理解,我必须使用20个左右的Provider<T>注射,然后使用我需要的那个,这对我来说似乎相当过分。有没有办法像inst(Provider<T>).get(MyAnnotation.class)那样绑定特定的实现,然后只将Provider注入我的班级?

2 个答案:

答案 0 :(得分:2)

注入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将两者捆绑在一起。

答案 1 :(得分:1)

如果您只想以编程方式获取实例,则可以注入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);
  }
}