确保在Guice中只加载一次模块

12
我需要处理Guice依赖注入时,不知道如何在模块中处理依赖关系。 在Guice中,每个模块都由一个实例提供。因此,如果我有一个需要某个服务的模块,它会创建该模块并将绑定添加到该服务,然后安装它(binder.install(module))。现在我有两个独立的模块,完全可以独立使用,并且都安装了相同的数据库模块。在单独使用这两个模块时没有问题,但是如果这两个模块都在同一个应用程序中使用会发生什么?数据库模块将由两个独立的模块加载,这是不正确的。是否有一种方法可以询问绑定器是否已经绑定了某种类型?我不能使用getProvider来检查,因为返回的只是LookupProvider,无论是否已经绑定。那么如何处理这种情况呢?更新:看起来Guice无法提供以下功能:1.检查是否已加载给定模块。2.检查是否已绑定给定类。3.使用提供者进行配置以能够进行分布式配置(即能够配置被贡献对象的模块)。
3个回答

16

Guice具有两个功能来处理这种情况。第一个是模块去重。这意味着如果安装了两个等效的模块(由equals()hashCode()确定),只有一个configure()方法将运行。然而,这种解决方案有些脆弱,因为它不能经受SPI转换、Modules.override()等。

第二个,也是我认为更好的解决方案,是绑定去重。这意味着Guice将接受完全重复的绑定。因此,如果您的模块执行bind(Interface.class).to(Implementation.class)操作,即使它的configure()方法运行了两次,Guice也可以很好地处理重复绑定。


所以我需要自己实现吗?比如将模块分组为依赖项,并以某种方式解决它们之间的依赖关系。从代码中我理解到,模块按从左到右或从前到后的顺序执行。 - Martin Kersten
模块安装的顺序应该是不重要的。这就是为什么没有办法检查是否已经创建了“绑定”的原因。 - Tavian Barnes
是的,但代码只是按照给定的模块列表向下遍历。最终,为了克服这个重要的缺陷,我需要在Guice代码中添加更多内容。 - Martin Kersten
我添加了第二个答案,描述了我目前的做法,但由于你的回答在问题的意义上是正确的,所以我会接受你的回答。感谢你的帮助。 - Martin Kersten
1
基本上,我对这个声明有异议:“数据库模块将由两个模块独立加载,这是不正确的。” 我认为,如果您正确设计您的模块,安装模块两次是可以的。 - Tavian Barnes

0

1
绑定去重至少从Guice 3开始就存在了。您链接的提交只是更改了它在多绑定中的实现方式。 - Tavian Barnes

0

由于Guice不支持某些所需功能,因此必须进行仿真。 multibinder代码提供了一个想法。我目前使用的另一个想法是在注入器构建过程中使用反射查找最顶层绑定器。知道这个绑定器后,可以轻松添加所需的元信息并跟踪某些对象。

这些元信息将在构建过程完成后被删除。

通常一次只构建一个注入器,但为了确保我们应该防止这种情况发生。

因此,请查看单个最重要的Binder实现(RecordingBinder)。它提供了一个parent字段,我们可以遍历到根绑定器元素。通常,Guice将使用单个最重要的绑定器,但在私有模块的情况下除外。

另一个想法并不那么安全,但不需要反射,即使用线程本地变量,如果您可以确保一次只构建一个Guice注入器。

能够识别构建过程并跟踪同时使用的构建器,人们就能够向Guice添加任何类型的附加逻辑,例如防止重复安装依赖项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接