在 Guice 中管理复杂的生命周期
Managing complex life cycles in Guice
我 运行 遇到了这样一种情况,我有一个数据对象图,并想为该图上的每个节点创建一个服务。问题是该服务(及其依赖项)依赖于它们所服务的节点。像这样:
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
的 new 实例,以及 Service
的任何依赖项的新实例在图表上。
所以现在我有几个选择:
guice
由一家辅助注射工厂提供支持。这就是我们目前正在做的,并且要求对节点的依赖是 curried 通过所有服务所依赖的,如果它们也依赖 node
。换句话说,如果我在这里使用辅助注入工厂,我必须为 service
依赖的每个 class 使用它,这是令人讨厌的。
- 我可以使用我们所说的嵌套引导程序,即带有新注入器的新模块,实际上是一个新环境,在该环境的设置中我可以写
bind(Node.class).toInstance(node)
。此代码将在第一次访问时执行,并缓存其结果。
- 我可以使用 guice 的自定义范围(我认为)。
我们在几个地方做了第二个,因为我和我的团队不知道自定义范围。我们现在有了自定义作用域的另一种用途,我必须承认它的实现比我想要的要复杂得多。关注 this guide 会有所帮助,但很明显我将不得不重新钻研线程安全领域,而我上次访问那里并不是那么愉快。
我应该使用什么 guice 工具来获得这种行为?
你可以为你想要的片段注入Injector
和create a child 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(/* ... */)
}
}
尽管可以对作用域执行类似的操作,但请记住,作用域仅用于识别 when to create a new object versus when to return the same object。这意味着您可以创建一个 @NodeScoped
范围并确保在处理给定节点时返回相同的对象,但是您仍然需要绑定某种 @NodeScoped NodeHolder
来在您潜水时保存您的节点in. 而不是保留和填充这个单独的持有者,子注入器会让你直接请求一个节点,这可能会使你的代码更容易理解和测试。
另请参阅:
- Guice assisted injection deeper down the dependency hierarchy
我 运行 遇到了这样一种情况,我有一个数据对象图,并想为该图上的每个节点创建一个服务。问题是该服务(及其依赖项)依赖于它们所服务的节点。像这样:
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
的 new 实例,以及 Service
的任何依赖项的新实例在图表上。
所以现在我有几个选择:
guice
由一家辅助注射工厂提供支持。这就是我们目前正在做的,并且要求对节点的依赖是 curried 通过所有服务所依赖的,如果它们也依赖node
。换句话说,如果我在这里使用辅助注入工厂,我必须为service
依赖的每个 class 使用它,这是令人讨厌的。- 我可以使用我们所说的嵌套引导程序,即带有新注入器的新模块,实际上是一个新环境,在该环境的设置中我可以写
bind(Node.class).toInstance(node)
。此代码将在第一次访问时执行,并缓存其结果。 - 我可以使用 guice 的自定义范围(我认为)。
我们在几个地方做了第二个,因为我和我的团队不知道自定义范围。我们现在有了自定义作用域的另一种用途,我必须承认它的实现比我想要的要复杂得多。关注 this guide 会有所帮助,但很明显我将不得不重新钻研线程安全领域,而我上次访问那里并不是那么愉快。
我应该使用什么 guice 工具来获得这种行为?
你可以为你想要的片段注入Injector
和create a child 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(/* ... */)
}
}
尽管可以对作用域执行类似的操作,但请记住,作用域仅用于识别 when to create a new object versus when to return the same object。这意味着您可以创建一个 @NodeScoped
范围并确保在处理给定节点时返回相同的对象,但是您仍然需要绑定某种 @NodeScoped NodeHolder
来在您潜水时保存您的节点in. 而不是保留和填充这个单独的持有者,子注入器会让你直接请求一个节点,这可能会使你的代码更容易理解和测试。
另请参阅:
- Guice assisted injection deeper down the dependency hierarchy