基本上我的问题归结为如何让这个测试通过:
private static class DefaultModule extends AbstractModule {
@Override protected void configure() {
}
}
private static class ParentModule extends DefaultModule{}
private static class ChildModule extends DefaultModule {}
private static class DependsOnInjector{
@Inject
public Injector depdendency;
}
@Test
public void when_instancing_a_class_that_depends_on_an_injector_it_should_yield_the_most_childish(){
//childish :p
Injector parent = Guice.createInjector(new ParentModule());
Injector child = parent.createChildInjector(new ChildModule());
DependsOnInjector objectWithInjector = child.getInstance(DependsOnInjector.class);
assertThat(objectWithInjector.depdendency).isSameAs(child);
}
但是也许我错过了这一点:堆栈溢出会让你相信做我正在做的事情是一种罪过(引入了一个参考注射器的工厂,当你问他们时他们只是转发给你制作一个产品,而我正在做的就是服务定位器,这是一个不好的举动。但我没有看到解决方法。
我有一个名为'Visualization'的界面,有7个实现者。运行时,根据您的数据集,我们选择一组这些可视化器来创建和渲染。对于具有Injector字段的工厂,我只需添加一个方法
public <TVis extends Visualization> TVis makeVisualization(Class<TVis> desiredVisualizationType){
return injector.getInstance(desiredVisualizationType);
}
我认为让工厂保留一个IOC容器作为一个字段的唯一选择是拥有7个guice的辅助注入工厂,每个实现一个,由交换机选择。那太讨厌了。
这是几个例子中的一个。我真的很喜欢获得最本地注射器的好方法。
编辑,澄清:
有很多地方可以方便地将注射器包装在某种解码器中。可视化器是一个实例,但还有几个。感谢Map绑定提示。我现在遇到的问题是我们的可视化工具(无论好坏,我怀疑更糟)希望每次需要时都可以实例化。所以即使使用地图绑定,我仍然需要将一个注入器注入我的可视化器 - 解码逻辑类中,不是吗?
关于我有多少个模块: 我目前有4个guice模块:一个共享的模块,它有很多我的大(真正)单身服务注册了它,然后一个用于我们的“托管”用户界面,然后一个用于我们的“问题设置”用户界面,另一个用于我们的“外部”工具“UI(实际上我们的测试环境还有一个)。后两个UI模块中有任意数量,并且每个模块都有一些很晚才创建的对象。没有使用子模块的含义我相信我会留下几个地图绑定器,每个都在运行时添加绑定(然后,大概是为了内存泄漏,处理时的某种删除逻辑)。在我看来,拥有我的(组合!)guice模块树(阅读:不是继承树!)
感谢您的帮助,感谢现有的建议。
答案 0 :(得分:4)
我有一个名为'Visualization'的界面,有7个实现者。 当您运行时,根据您的数据集,我们选择一组这些 用于创建和渲染的可视化工具。
如果您的可视化工具集已修复,请考虑使用普通binding annotations。这是用于区分同一接口的多个实现的最简单方法。你不需要多个注射器。
如果您的可视化工具集未修复(例如,这些可视化工具是插件),那么您的任务将使用MapBinder
整齐地解决。有了它,您也不需要多个注射器,您可以在单个注射器内定义所有Visualization
:
public class VisualizationsModule extends AbstractModule {
@Override
protected void configure() {
MapBinder<Class<Visualization>, Visualization> binder =
MapBinder.newMapBinder(binder(), new TypeLiteral<Class<Visualization>>() {},
TypeLiteral.get(Visualization.class));
binder.addBinding(Visualization1.class).to(Visualization1.class);
binder.addBinding(Visualization2.class).to(Visualization2.class);
// etc
}
}
然后你可以注入一个Map<Class<Visualization>, Visualization>
:
@Inject
public SomeClass(Map<Class<Visualization>, Visualization> visualizers) {
...
}
您可以选择任意密钥,而不仅仅是Class<Visualizer>
,这取决于您的业务需求。如果可视化器是插件,则应该使用某种插件标识符作为密钥。
答案 1 :(得分:3)
要回答您的第一个问题,您可以通过向bind(DependsOnInjector.class);
添加明确的ChildModule
来获取所需的注射器。否则,“just-in-time bindings created for child injectors will be created in an ancestor injector whenever possible。”
答案 2 :(得分:2)
如果您只想在运行时获取正确的实例,为什么不能只在模块中添加@Provides
方法来实例化Visualization
?