20

假设我有两个应用程序共享同一个库。这个库包含常见的类,如 DAO、Utils 等。共享库中的所有内容都与 Guice 连接。我的两个应用程序依赖于这个库,但不直接依赖于 Guice。

 ______    ______    ______
|      |  |      |  |      |
| APP1 |->| LIB  |<-| APP2 |
'------'  '------'  '------'

我目前使用这样的东西:

static <T> Utils.getInstanceOf (Class<T> type);

这只是一个包装器:

injector.getInstance (Class<T> type);

但是 guice 文档说:

如果可行,请避免使用此方法,而是让 Guice 提前注入您的依赖项。

那么,为这两个应用程序提供依赖注入而无需在 Guice 模块中手动绑定它们的最佳方式是什么?

4

5 回答 5

15

那么,为这两个应用程序提供依赖注入而无需在 Guice 模块中手动绑定它们的最佳方式是什么?

没有这样的方法。您要么完全接受 Guice,要么不使用它并显式传递您的依赖项。好吧,以这种方式构建代码,因此您永远不会直接创建类依赖项,而是通过构造函数传递它们,也可以称为“依赖注入”,但我确定这不是您的意思。如果您不想在您的应用程序中使用 Guice,您将无法获得比 更好的东西getInstance(),这很丑陋,尤其是因为您使用的是静态包装器。

理想情况下,您的库应该提供一个可以Guice.createInjector()在应用程序中安装的模块,或者相反,库应该提供一个Injector实例,您可以通过使用createChildInjector()和提供特定于应用程序的模块在应用程序中使用该实例。这种方法的轻微修改是将特定于应用程序的模块传递给库,因此它们将用于创建Injector. 我最近在自定义的类 servlet 接口上编写了基于 Guice 的 API,该接口使用最后一种方法根本不支持任何类型的 DI,并且运行良好。

在 servlet 或 Jersey 环境中使用 Guice 一点也不难。例如,后者与 Guice 具有开箱即用的集成(至少在 1.x 版本中)。Guice servlet 扩展也很好很方便。试一试,自己看看。

于 2013-10-11T07:04:29.223 回答
4

static <T> Utils.getInstanceOf (Class<T> type);

你最终得到的是一个Service Locator

injector虽然在一些小情况下,逃到其他创建对象中是可以接受的,但我不认为这是其中之一。您最终发现了服务定位器的所有缺点,并且可以通过使用您已经使用的工具来获得所有优点。

于 2013-10-11T09:43:58.353 回答
4

如果您有一个方法需要在运行时创建类 C 的新实例,请将 Provider 绑定到您的类。C 将以通常的方式被绑定,例如

public CModule extends AbstractModule {
    @Overide
    public void configure() {
        bind(C.class).to(CImpl.class);
    }
}

创建 C 实例的类如下所示:

class UserOfC {
    private Provider<C> cProvider;
    ...

    @Inject
    UserOfC(Provider<C> cProvider, ...) {
        this.cProvider = cProvider;
        ...
    }

    public void doSomethingWithAC (...) {
        C myC = cProvider.get();  // not a singleton; new instance created!
        ...
    }
}

Guice 支持免费提供 Provider 注入。如果 C 被绑定,您可以像注入 C 实例一样容易地注入 Provider。

其他建议:

我强烈建议您在构建时注入所有依赖项,如果可能的话,即使它需要编写更多的代码行。我已经使用 Guice 多年,还没有需要部分构建或任何其他高级功能。

当我面临部分注入的需求时,我一般会写自己的工厂。我发现编写代码时更容易理解和调试。

于 2018-01-15T01:00:54.933 回答
2

使用注入器的“通常”模式是在项目的某个顶级入口点中设置它(在 servlet 场景中,使用 Guice-Servlet,这将是 GuiceServletContextListener)。为了模块化,您可能希望在某个依赖项的入口点配置一个单独的注入器,并使其负责连接该依赖项。如果您在依赖项中同时需要单个绑定和来自父项目的绑定,那么您可以创建一个子注入器,如果未找到绑定,则该子注入器委托给其父项目。Guice 支持这一点。

但是,您想在依赖项中设置一个注入器并在您的主应用程序中使用它,这对我来说似乎很奇怪。这意味着依赖项知道主应用程序所需的所有绑定。我不太确定你想用这种方法实现什么。您的两个应用程序是否具有相同/非常相似的绑定设置并且您不想重复它?在这种情况下,您应该定义一个包含所有绑定配置的模块一次(可能在依赖项中),并在每个应用程序的入口点设置注入器时使用它。就你的情况而言。

对你的一般问题。我认为避免明确通过注射器是一种很好的做法。每当你这样做时,你就违背了将依赖注入作为一个透明项目的想法,并且你将自己绑定到一个具体的注入框架。在大多数情况下,您可以通过使用ProvidersFactories来避免对注入器的显式引用。

于 2013-10-11T07:53:28.823 回答
0

是的,以这种方式通过注射器是可以的。

即使我们对我们的 wicket 应用程序做了类似的事情,所以对于非 wicket 页面,我们只是简单地使用injector.get.inject(this)并传入构造函数。

它完美无缺。

希望这可以帮助。

于 2013-10-11T07:20:24.870 回答