【问题标题】:How to inject Injector?如何注入喷油器?
【发布时间】:2010-02-01 11:13:42
【问题描述】:

情况:我需要在某些FooClass 中进行惰性依赖实例化,因此我将Injector 作为构造函数参数传递给类。

private final Injector m_injector;

public FooClass(@Named("FooInjector") Injector injector) {
m_injector = injector;
}

但 guice 不允许绑定核心类(注入器、模块等)。解决办法是什么?

【问题讨论】:

    标签: dependency-injection guice


    【解决方案1】:

    您不应该直接使用Injector。而是传入Provider<FooClass>。此外,您应该在使用FooClass 的地方注入提供程序。

    private final Provider<FooClass> provider;
    
    @Inject
    public ClassWhereFooIsUsed(Provider<FooClass> provider) {
        this.provider = provider;
    }
    
    .... somewhere else
    FooClass f = provider.get(); // This is lazy
    

    【讨论】:

    • 谢谢!我会尝试延迟初始化。但是真的没有办法注入Injector吗?
    • 可以用@Inject Injector injector获取注入器,可以在构造函数/字段/方法上。
    • 你试过了吗?如何配置模块? Guice 限制绑定到核心类:“不允许绑定到核心 guice 框架类型:Injector。”
    • @AlexM:如果你真的需要,看看childInjectors。一般来说,它们不应该是必需的,你应该只使用一个注射器。有例外,但很少见。
    • 为什么需要多个喷油器?我真的无法想象。
    【解决方案2】:

    正如其他人已经回答的那样,您可以简单地使用@Inject Injector,因为 Guice 定义了绑定本身。

    通常,您的应用程序中只需要一个Injector,静态变量是一种比注入它更容易存储和访问单例的方法。在我们的网络应用程序中,我们使用stripes-guicer,并在需要时从其静态方法GuiceInjectorFactory.getInjector() 中获取Injector(例如在我们的Hibernate 拦截器中)。

    “您不应该直接使用 Injector”的建议让我有些困惑。除了调用injector.getInstance()injector.injectMembers() 之外,我还能如何注入实例?没有办法。是的,您可以定义 Provider 方法,但它们永远不会被调用,除非某处使用 Injector。是的,有些模块为您使用Injector,例如ServletModule;您必须自己创建Injector,但之后您可以将其留给ServletModule

    所以在某些情况下,您可以避免直接使用Injector,但这并不意味着您“不应该”使用它。如果您在没有任何可选模块的情况下单独使用 Guice,那么您“应该”到处使用 Injector,因为没有其他方法可以触发注入。 (我认为整天在框架内编写代码的开发人员有时会忘记有些人实际上实例化了他们自己的对象。)

    【讨论】:

    • 我不相信您已经理解 Guice 背后的基本原理。它明确旨在避免使用静态字段和状态,并且您应该很少直接引用 Injector 本身。您可以通过使用 @Inject 声明依赖项来注入实例,而不是在注入器上调用 getInstance()
    • 我唯一的一点(我说得相当冗长)是你必须从某个地方开始;这是一个先有鸡还是先有蛋的问题。您不能only 用@Inject 装饰方法并期望任何事情发生。某处的某些东西必须调用 injector.getInstance() 或 injector.injectMembers() 来启动它。
    • 在反射上下文中呢?哪里在编译时不知道从上下文中想要的类?
    • 与其说是“你不应该直接使用Injector”,不如说是“你不应该注入 Injector”。 Guice 提供了很多关于模块创建的检查,如果模块 inside 的东西最终自己注入了Injector,这些检查都不起作用。最初从Guice.createInjector(...myModules) 手动创建的Injector 非常好用。
    【解决方案3】:

    正如@gpampara 所说,Provider&lt;T&gt; 应该用于延迟/可选初始化。此外,正如我在回答您的其他问题时所说,您应该避免在几乎所有情况下在代码中引用 Injector

    也就是说,在 Guice 创建的类中,创建对象的 Injector 可以通过声明对 Injector 的依赖项来注入。 Injector 自动可用于注入,无需您声明任何绑定。

    如果您确实注入了Injector,您应该考虑一下为什么要这样做。为什么不直接声明对类所依赖的实际接口/类的依赖关系?向构造函数添加新的依赖项就像通过代码中其他位置的 Injector 检索某个依赖项的实例一样容易,而且它也使代码更易于理解。

    【讨论】:

    • 回复:“为什么要这样做” - 例如,我想在引导后即时创建动态代理。我的问题:stackoverflow.com/questions/34252268/…
    • 另一个用例:我正在使用第三方库从存储/网络中解组域对象,并希望允许它们从 DI 图中请求服务。
    • 回复:“你为什么要这样做”。我正在使用 Quartz,在工作中我想调用另一个服务 --> 我必须创建自己的 JobFactory。要实例化一个工作,我需要一个注射器。这就是重点。
    【解决方案4】:

    可能不应该注入Injector 实例的参数非常有效,但与任何规则一样,也有例外。

    我有一个工厂类,它接受需要为其提供实例的类引用。这些实例不一定是已知的(实际上,它们是已知的,但有很多而且可能还有更多),所以我不能为所有这些实例创建 Providers。

    public class ThingFactory {
        private Injector injector;
    
        @Inject
        ThingFactory(Injector injector) {
            this.injector = injector;
        }
    
        public <T> T getInstance(Class<T> aClass) {
            return injector.getInstance(aClass);
        }
    }
    

    我的应用程序中真正的类是扩展和覆盖另一个类——这就是为什么这个类基本上是 Guice 的传递。

    【讨论】:

    • 一个例子是使用 Quartz 时的 JobFactory。 Tks
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2014-07-03
    • 1970-01-01
    相关资源
    最近更新 更多