12

我在理解 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 实例。我真的不明白为什么开关应该很重要 - 我可以看到后一种方式如何“更好”,但我希望两者都能正常工作,所以我只是想知道我是否在这里遇到问题...... .

4

1 回答 1

13

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

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

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

于 2011-11-08T22:58:20.977 回答