Java Guice injectionor.getInstance() - 好的做法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19311702/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 15:59:26  来源:igfitidea点击:

Guice injector.getInstance() - good practice?

javadependency-injectionguice

提问by albogdano

Let's say I have two applications sharing the same library. This library contains common classes like DAOs, Utils, etc. Everything in the shared library is wired with Guice. My two apps depend on this library but do not have a direct dependency on Guice.

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

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

I currently use something like this:

我目前使用这样的东西:

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

which is simply a wrapper for:

这只是一个包装:

injector.getInstance (Class<T> type);

But the guice docs say:

但是 guice 文档说:

When feasible, avoid using this method, in favor of having Guice inject your dependencies ahead of time.

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

So what's the best way to provide dependency injection for the two apps without having to manually bind them in a Guice module?

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

采纳答案by Vladimir Matveev

So what's the best way to provide dependency injection for the two apps without having to manually bind them in a Guice module?

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

There is no such way. You either embrace Guice totally or do not use it and pass your dependencies explicitly. Well, structuring your code in such way so you never directly create class dependencies, passing them instead through a constructor, also may be called 'dependency injection', but I'm sure this is not what you meant. If you do not want to use Guice in your apps, you won't be able to get anything better than getInstance(), which is ugly, especially because you're using staticwrapper.

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

Ideally your library should provide a module which you can install via Guice.createInjector()in your applications, or, in the other way around, the library should provide an Injectorinstance which you can use in your applications by using createChildInjector()and providing application-specific modules. Slight modification of this approach is passing application-specific modules to the library so they will be used to create Injector. I have recently written Guice-based API over custom servlet-like interface which didn't support any kind of DI at all using the last approach, and it is working perfectly.

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

It is not at all hard to use Guice in servlet or Jersey environment. The latter, for example, has out-of-the-box integration with Guice (at least, in 1.x versions). Guice servlet extensionis also very good and convenient. Just try it and see for yourself.

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

回答by Ashish

Yeah it ok to pass injector this way.

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

Even we have done something similar with our wicket application, so for non non-wicket pages we have simply used injector.get.inject(this)and passed in the constructor.

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

and it works perfect.

它完美无缺。

Hope this helps.

希望这可以帮助。

回答by Sven Amann

The "usual" pattern of using an injector is to set it up in some top-level entry point of you project (in a servlet scenario, using Guice-Servlet, this would be the GuiceServletContextListener). You may want to configure an individual injector at an entry point to some dependency and make it responsible for wiring that dependency, for the sake of modularization. If you want both, individual bindings and the bindings from the parent project, in your dependencies, than you can create a child injector that delegates to its parent if no binding is found. Guice supports this.

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

However, it seem strange to me that you want to set up an injector inside a dependency and use it in your main app(s). This would mean that the dependency knows about all bindings required by the main app(s). I'm not quite sure what you are trying to achieve with this approach. Is it that your two apps have the same/a very similar binding setup and you don't want to repeat it? In this case you should define a module with all that bindings configurations once (maybe in a dependency) and use it when setting up the injector at the entry points of each of your apps. That much in regard to your scenario.

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

To your question in general. I think its good practice to avoid explicitly passing the injector. Whenever you do this, you work against the idea of dependency injection as being a transparent project and you tie yourself to a concrete injection framework. In most cases you can avoid explicit references to the injector by using Providersand Factories.

对于你的问题。我认为避免显式传递注入器的好做法。每当您这样做时,您都会反对将依赖注入作为一个透明项目的想法,并将自己绑定到一个具体的注入框架。在大多数情况下,您可以使用ProvidersFactories避免显式引用注入器。

回答by Michael Lloyd Lee mlk

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

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

What you have ended up with is a Service Locator.

你最终得到的是一个Service Locator

While in a few small cases this it is acceptable for the injectorto escape into other creational objects, I don't think this one of them. You have ended up with all the disadvantages of a Service Locator and all the advantages can be had by using the tool you are already using.

虽然在一些小情况下injector,逃逸到其他创建对象是可以接受的,但我不认为这是其中之一。您已经解决了 Service Locator 的所有缺点,并且可以通过使用您已经在使用的工具获得所有优点。

回答by Eric Mintz

If you have a method that needs to create a new instance of class C at runtime, bind a Provider to your class. C would be bound in the usual way, e.g.

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

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

The class that creates C instances would look like this:

创建 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 supportes Provider injection free for nothing. If C is bound, you can inject a Provider as easily as you can inject an instance of C.

Guice 免费支持 Provider 注入。如果绑定了 C,则可以像注入 C 的实例一样轻松地注入 Provider。

Additional Suggestions:

其他建议:

I strongly recommend that you inject all dependencies at construction, if at all possible, even if it requires writing a few more lines of code. I've used Guice for years, and have yet to need partial construction or any other advanced feature.

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

When I am faced with the need for partial injection, I generally write my own factory. I find it much easier to understand and debug when I write the code.

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