我遇到了这样一种情况,我有一个数据对象图,并且希望为这个图上的每个节点创建一个服务。问题是此服务(及其依赖项)依赖于它们所工作的节点。像这样:
class Visitor {
void enter(Node node){
Service service = guice.create(node)
service.doComplexDomainLogic(/*some runtime information about the graph and the path to get here, other things*/)
}
}
请注意,这里我的目的是为图上的每个节点创建Service
的新实例,以及Service
的任何依赖项的新实例。
现在我有两个选项:
-
guice
由辅助注射厂支持。这就是我们目前正在做的,并且要求对节点的依赖是通过所有服务依赖的进行curry,如果它们也依赖于node
。换句话说,如果我在这里使用辅助注入工厂,我必须为service
依赖的每个类使用它,这是令人讨厌的。 - 我可以使用我们所说的嵌套引导器,也就是说,一个带有新注入器的新模块,实际上是一个新环境,在该环境的设置中,我可以编写
bind(Node.class).toInstance(node)
。此代码将在第一次访问时执行,并缓存其结果。 - 我可以使用guice的自定义作用域(我认为)。
我们在几个地方做了第二种,仅仅是因为我和我的团队不知道自定义作用域。现在我们有了自定义作用域的另一种用法,我必须承认它的实现比我希望的要复杂得多。下面的指南会有所帮助,但很明显,我将不得不回到安全的地方,我上次的访问并不那么愉快。
我应该使用什么指导工具来获得此行为?
你可以注入Injector
,并为你想要的部分创建一个子注入器。子注入器可以让你修改对象图,并访问父注入器的所有依赖项,但你可以随心所欲地访问你的节点。
class Visitor {
@Inject Injector injector;
void enter(final Node node) {
Service service = injector.createChildInjector(new AbstractModule() {
@Override public void configure() {
bind(Node.class).toInstance(node);
// Anything that does require a Node should be bound here, because
// you can't define it in the parent due to the unsatisfied binding.
bind(SomeInterface.class).to(SomeClassThatRequiresNode.class);
}
}).getInstance(Service.class);
service.doComplexDomainLogic(/* ... */)
}
}
虽然可以用作用域做类似的事情,但请记住作用域只是用来识别何时创建新对象和何时返回相同对象。这意味着您可以创建@NodeScoped
作用域,并确保在处理给定节点时返回相同的对象,但是您仍然需要绑定某种@NodeScoped NodeHolder
来保存您的节点。子注入器可以让你直接请求一个Node,而不是保留和填充这个单独的holder,这可能会让你的代码更容易理解和测试。
参见:
- 向导辅助注入
- 如何在过滤器等向导中连接N个节点链