我刚刚开始使用 Guice,在阅读了文档、浏览了几本书并观看了 2009 年 Google I/O 演讲之后,我正在尝试转换一个依赖于一些全局数据结构的 Thrift 项目。目前,它们是在 thrift 服务器启动时创建的,并传递给每个请求的处理程序。它们也用在代码的每个部分!本质上是单身人士。
据我了解,最佳实践是在主方法中创建注入器并加载所有模块一次。
我不确定如何在代码中的其他地方使用这个注入器。我应该将它包装在一个单例类中并用
乱扔我的代码吗Injector injector = InjectorInstance.get();
ClassA obj = injector.getInstance(ClassA.class);
或者有什么我不知道的方法
ClassA obj = Guice.getLastInjector().getInstance(ClassA.class);
我还找到了传递 Provider 的建议,但我不确定这比在调用堆栈中传递实际数据结构更好。
如果有人可以解释推荐的模式,或者更好地向我发送一个使用 guice 的优秀开源项目的方向,我将不胜感激!
对于 Guice 来说,这个想法是你拥有一个完整的依赖关系图,每个依赖关系都保留对其整个生命周期所需事物的引用:
class EntryPoint {
public static void main(String[] args) {
YourApp yourApp = Guice.createInjector(yourListOfModules())
.getInstance(YourApp.class);
yourApp.run();
}
}
class YourApp {
@Inject DependencyA dependencyA;
}
class DependencyA {
@Inject DependencyB dependencyB;
}
class DependencyB {
/** This is injected once, so you'll always only get the same instance. */
@Inject DependencyC dependencyC;
/** By injecting the provider, you can get multiple instances. */
@Inject Provider<DependencyD> dependencyD;
}
Guice 负责管道,因此 YourApp 和 DependencyA 无需担心 DependencyB 是否需要 DependencyC 或 DependencyD。从这个意义上说,您永远不会调用
new
:Guice 负责为您创建每个 @Inject
ed 依赖项,然后提供其依赖项。
如果您尚未深入了解依赖项(即您仍然在代码中调用
new
),您将无法再从手动构建的类访问注入器。在这种情况下,您可能需要使用 getInstance
或 getProvider
并将其存储在静态字段中。 Guice 还将帮助您使用 requestStaticInjection 来完成此操作,这对于长期的 Guice 设计来说不是很好,但可以帮助您处理遗留代码或过渡到 Guice。
更新: 可能会很想走得更远,就像在静态实例持有者模式中一样:
class InjectorHolder {
static Injector injector;
static {
// WARNING: Poor practice as described below.
injector = Guice.createInjector(new YourModule1(), ...);
}
}
然而,这需要一个众所周知的繁重过程——对于非常大的图,Guice 启动可能非常慢,特别是考虑到反射、模块评估和急切的单例初始化——并将其全部放在一个可以在任意时间运行的地方。 阻止进一步的类加载的任意线程。它还意味着您的 Injector 持有者将是一个有效的单例,因此您不是将 Injector 驱动的实例本地放置在您的任意类中(这已经是一种务实的选择,但与本地声明性依赖项兼容),而是暗示了其他地方的其他对象您的图表将访问您的支架以到达其注射器。这可能意味着您的 DI 对象可能会从秘密的全局静态服务定位器获取其依赖项,而不是在字段和构造函数参数中以声明方式表达它们。
出于这些原因,您在应用任何全局静态持有者时应该格外小心:它可能在小图中看起来和表现良好,或者可能是完全迁移到更好的 Guice 实践期间的一个引理,但 Guice 是为大型企业而设计和优化的DI 部署,所以我必须假设这就是您和其他未来读者的用例。如果您投资此 InjectorHolder 模式,那么随着图表的增长,您可能会发现其相关的反模式在可读性和可预测性方面比许多其他解决方案(包括手动 DI 和正确使用 Guice)更差,并且对该模式的投资可能会增加您的使用最终正确模式的迁移时间和认知开销。