我读到,从 DI 机制显式请求对象实例被认为是 DI/IoC 的一般反模式。这是因为,当对象进入作用域时,它应该已经注入(inject)了它所需的所有依赖项。在 Guice-land 中,这样的反模式将表示为:
Service svcImpl = (Service)injector.getInstance(Service.class);
显然,这种反模式的一个异常(exception)是引导/依赖解析阶段,在该阶段,您向 Guice 询问所有顶级根(“根”是指所有其他对象从它流出)对象。
有趣的是,经过详尽的在线搜索后,我找不到此引导过程的任何实用的、工作的代码示例!我想象它看起来像这样:
public void bootstrap() {
RootObj1 root1 = (RootObj1)injector.getInstance(RootObj1.class);
RootObj2 root2 = (RootObj2)injector.getInstance(RootObj2.class);
this.root1 = root1;
this.root2 = root2;
// Since all objects flow from these two "root" dependencies, bootstrapping
// is complete. root1 and root2 contain all the dependencies the application
// needs from here on out, and the "injector" object is no longer needed.
// More importantly, injector is never used anywhere else in the code, and
// therefore the code is not in violation of this anti-pattern.
}
这是正确的,还是我在这里偏离了基地?我问只是因为我找不到任何工作示例!
当我写这篇文章时,我开始重新审视自己,因为这似乎不可行/不切实际。
这是因为,实际上应用程序的依赖关系图将非常庞大,包含许多独立的、不同的“依赖关系树”,每个依赖关系树都有自己的根。这将导致需要某种 Bootstrapper
对象,负责返回每个树的根,以便代码库中的所有其他对象都可以向它们的“树”请求适当的根对象属于。这听起来已经非常令人费解了。
关于如何在现实世界中实践引导的工作代码示例可能有助于让我更清楚地了解这一点。提前致谢!
最佳答案
我认为你很难找到一个好的例子的原因是你让它变得比需要的更复杂。引导并不比您的代码片段更复杂,只是您可能需要调用 root1
或 root2
上的方法来让您的应用程序开始执行它所做的任何操作!
剩下的就由 Guice 处理。在执行过程中实例化的任何对象都可以通过 @Inject 注释的构造函数(或方法)从 Guice 获取所需的内容。不需要有一个 Boostrapper 对象来控制所有树的所有根,因为 DI 容器管理所有实例。如果一棵树中的对象需要另一棵树中的对象,您只需 @Inject
即可!无需“询问”Bootstrapper 对象。对于具有 ServiceLocator 背景的人来说,有时很难想象,但这确实是一种更具凝聚力的类设计方式。
Guice 有多种用于管理依赖图的工具。不同的依赖关系树通过模块进行管理,这些模块只是内聚绑定(bind)的集合。因此,Guice 鼓励您封装功能并让注入(inject)器解决相互依赖性。此外,Guice 在需要之前不会实例化图(单例除外,可以立即加载),并且开发人员可以使用 Provider
接口(interface)和方法显式延迟实例化。
如果您解释一下您想要使用 Guice 的应用程序类型,或者解释一下您习惯的应用程序类型,也许会有帮助。这将使我们更好地了解什么是没有意义的。
关于java - Guice:引导和依赖图解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10141950/