如何使用两个安装公共依赖模块的Guice模块

der*_*ink 21 java guice

我正在开展一个由四部分组成的项目:

  • Main将所有事物融合在一起的项目.这包含public static void main(String... args)入口点.
  • 零件 A
  • 零件 B
  • 第三方Common组件,这两个AB参考.

我正在使用Guice来处理所有四个部分之间的管道,这就是我的问题:
As和Bs主要的Guice模块中,我安装了一个扩展了一个模块的模块Common.在运行时,此设置失败,并显示以下错误:

common.SomeClass已配置绑定到common.AbstractCommonModule.configure().[ 来源 ]

原因是我要调用common.AbstractCommonModule.configure()两次; 一旦通过安装的子类实例common.AbstractCommonPrivateModule从组件Acom.a.MainModule.configure(),并从部件的第二时间Bcom.b.MainModule.configure().

只安装一个common.AbstractCommonPrivateModule in 实例Main不是一个选项,因为AbstractCommonPrivateModule实现了一个特定的binder方法bindComplicatedStuff(ComplicatedStuff),我只分别知道其中的参数AB.

我尝试通过将As和B各自的主要Guice模块包装在s中来解决这个问题PrivateModule.但是,由于下一个错误,此操作失败:

无法为%s创建绑定.它已经在一个或多个子注入器或私有模块上配置%s%n如果它在PrivateModule中,您是否忘记公开绑定?[ 来源 ]

在我的情况下,A's和B各自的主要Guice模块实际上是ServletModules - 显然我可以安装两次Main.

如何解决这些错误并安装AbstractCommonPrivateModule模块两次?

编辑:向GitHub上传了一些示例代码(有关一些细节的说明)

dim*_*414 15

而不是拥有AB安装Common,让他们requireBinding()的所需的类Common.然后依赖AB将需要安装的模块Common.这可能会感到有点奇怪,但它实际上是可取的,因为AB现在不太紧密耦合到Common.


更新

我安装两个ShiroWebModules 的原因是因为我希望ui模块中的Jersey资源只能使用一个Shiro配置(一个解密密码保护资源)来保护,而api模块中的所有Jersey资源都应该使用完全不同的方式来保护Shiro配置(仅将承载令牌理解为认证机制的配置).

从广义上讲,这是棘手的.Guice Injector为整个应用程序提供了一种做某事的方法(通常是一个接口的实现); 每个包装没有不同的机制.你的两个Module,SwsApiServletModuleSwsUiServletModule提供了许多相同的绑定,并将SwsModule它们安装在一起.实质上你说"Guice,请提供基于bearer-token的认证机制",然后在说"Guice,请提供基于密码的认证机制"之后立即说.它只能做一个或另一个,所以不是任意选择一个,而是快速失败.

当然,有很多解决方案,具体取决于您的需求.最常见的是使用绑定注释并使UI和API代码请求不同的注释.这样,您可以安装相同接口或类的两个不同实现(具有不同的注释).

这是一个例子:

package api;

public class ApiResources {
  @Inject
  public ApiResources(@ApiAuthMechanism AuthMechanism auth) {
    this.auth = auth;
  }
}

---

package api;

public class ApiModule implements Module {
  public void configure() {
    bind(AuthMechanism.class).annotatedWith(ApiAuthMechanism.class)
        .to(BearerTokenAuthMechanism.class);
  }
}

---

package ui;

public class UiResources {
  @Inject
  public UiResources(@UiAuthMechanism AuthMechanism auth) {
    this.auth = auth;
  }
}

---

package ui;

public class UiModule implements Module {
  public void configure() {
    bind(AuthMechanism.class).annotatedWith(UiAuthMechanism.class)
        .to(PasswordAuthMechanism.class);
  }
}

---

package webap;

public class WebappModule implements Module {
  public void configure() {
    // These modules can be installed together,
    // because they don't install overlapping bindings 
    install(new ApiModule());
    install(new UiModule());
  }
}
Run Code Online (Sandbox Code Playgroud)

您在评论中提到您无法控制正在安装的重叠绑定,因为它们来自第三方模块.如果是这种情况(我没有看到您的代码中发生了什么),出于安全原因,第三方可能不希望您执行您尝试执行的操作.例如,简单地绑定基于密码的机制可能会在整个应用程序中引入漏洞.可能值得尝试更好地了解第三方打算如何使用其模块.

另一个不理想但可以用于某些用例的选项是使用两个完全独立的Injector实例,每个实例具有一个绑定.然后,您手动将所需的实例直接传递给UI和API代码.这在一定程度上违背了Guice的目的,但并不总是错误的决定.利用孩子Injector小号可以使这种痛苦少.


另外,您的"示例代码"非常庞大,可能超过90%与此问题无关.将来请花点时间创建一个包含与手头问题相关的代码的SSCCE.没有人会筛选100多个Java文件和7,300多行代码来理解你的问题.这不仅会让那些试图帮助您的人更容易,而且只是尝试创建一个证明问题的SSCCE通常足以帮助您自己理解和解决问题.