【问题标题】:Guice eager/lazy singleton instantiationsGuice 急切/懒惰的单例实例化
【发布时间】:2011-11-08 16:12:24
【问题描述】:

我在理解 Guice 的单例实例化如何工作时遇到了一些麻烦。我已经阅读了可用的文档(这里 - http://code.google.com/p/google-guice/wiki/Scopes ),但我仍然无法弄清楚一些事情:

  1. 我已将 Guice 与 Tomcat 集成,并在 ServletModule 中设置了一些绑定:

    bind(MyServlet.class).asEagerSingleton();
    serve("myUrl").with(MyServlet.class);
    serve("myOtherUrl").with(MyOtherServlet.class);
    

    (其中 MyOtherServlet 类上面有一个 @Singleton 注释) 我的意图是有两个 servlet,其中一个被急切地实例化,而另一个则没有。然而,似乎“服务...与...”行会自动实例化 servlet 对象,即使该类未绑定为急切的单例。 我在上面附加的链接提到了在 Stage.Development 和 Stage.Production 下运行的 Guice 之间的区别 - 但是,即使我明确使用 Stage.Development (无论如何都是默认的),这种情况仍然发生。 有什么办法可以避免吗?

  2. (继续 1)为了确保 MyServlet 首先被实例化,即使现在所有 servlet 都急切地实例化,我在创建 Injector 时修改了模块(和绑定语句)的顺序,以便 MyServlet 的绑定首先出现。但是,我发现它仍然比其他一些绑定(非 servlet 类)晚实例化,这些绑定的形式如下:

    bind(MyInterface.class).to(MyClass.class).asEagerSingleton()
    

    即使那些其他绑定出现在模块/绑定顺序的后面。 我研究了一下,发现 Guice 在执行“bind ... asEagerSingleton()”之前,只是简单地实例化了由“bind ... to ... asEagerSingleton()”形式绑定的热切单例,所以我通过修改行来解决它:

    bind(MyServlet.class).asEagerSingleton();
    

    进入:

    bind(MyServletDummyInterface.class).to(MyServlet.class).asEagerSingleton()
    

    这确实有效。不过,我宁愿避免使用虚拟接口来解决这个问题,所以我想知道是否有人对此有更好的解决方案..?

  3. 我有两个 Guice 模块 - 一个 ServletModule 和一个 AbstractModule。 ServletModule configureServlets() 中包含以下绑定:

    serve("aUrl").with(SomeServlet.class); AbstractModule 的 configure() 具有以下绑定:

    bind(SomeImpl.class).asEagerSingleton();
    bind(SomeInterface.class).to(SomeImpl.class).in(Singleton.class);
    

此外,SomeServlet 类有一个 SomeInterface 类型的注入字段,并且在类的顶部有一个 @Singleton 注解。

现在,人们会期望在创建注入器时,SomeImpl 类将被实例化,并且相同的实例将被注入到 SomeServlet 实例中。如前所述,以“serve...with...”语句为界的 servlet 似乎也被急切地实例化,但无论哪种方式,仍然应该只实例化一个 SomeImpl 对象。然而由于某种原因,我在执行此操作时实例化了两个 SomeImpl 对象。 为了解决这个问题,我在 configure() 中混合了两行,而不是上面的,我有以下几行:

bind(SomeImpl.class).in(Singleton.class)
bind(SomeInterface.class).to(SomeImpl.class).asEagerSingleton();

然后它工作得很好,我只实例化了一个 SomeImpl 实例。我真的不明白为什么开关应该很重要 - 我可以看到后一种方式如何“更好”,但我希望两者都能正常工作,所以我只是想知道我是否在这里出错了...... .

【问题讨论】:

    标签: java singleton guice eager


    【解决方案1】:

    1) 没有办法避免这种情况,因为 Guice 在初始化它自己的过滤器管道时调用所有 servlet 的 init() 方法,从而构建它们。如果你真的需要这种懒惰的初始化逻辑,你应该把它放到 servlet 本身中(或者使用解耦的辅助类,或者......有很多方法,取决于你的用例)。

    2) 一般来说,Guice 的模块声明绑定,没有设计为具有精确实例化顺序的引导定义。如果您需要这样定义的实例化顺序,请按照所需顺序自己创建对象并通过bind(...).toInstance(...) 绑定它们。如果需要在自建实例中注入,可以使用requestInjection(...)(如果字段/方法注入足够,构造函数注入就比较麻烦了)。

    3) Guice 的范围适用于绑定键,而不是绑定值,Applying Scopes 描述了为什么只有您的第二个示例按预期工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-09
      • 1970-01-01
      相关资源
      最近更新 更多