Guice急切/延迟单例实例化

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,其中一个是急切地被实例化,而另一个则不是。然而,似乎“serve...with...”语句会自动实例化servlet对象,即使该类未绑定为急切的singleton。 我附上的链接提到了Guice在Stage.Development和Stage.Production下运行的区别,但即使我明确使用了Stage.Development(默认情况下),这种情况仍然发生。 有没有办法避免这种情况?

  • (接续1) 为了确保MyServlet首先被实例化,即使现在所有servlet都是急切地实例化,我修改了模块的顺序(以及绑定语句),使得MyServlet的绑定出现在第一位。然而,我发现它仍然比其他绑定(非servlet类的绑定)晚实例化,这些绑定的形式如下:

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

    尽管其他绑定出现在模块/绑定顺序中的后面。 我研究了一下,并发现Guice只是在执行“bind... to... asEagerSingleton()”形式的单例之前,实例化通过此形式绑定的单例,而不是通过“bind... asEagerSingleton()”绑定的单例。因此,我通过修改该行来解决它:

    bind(MyServlet.class).asEagerSingleton();
    

    转换成:

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

    那个方法确实可行。不过,我宁愿避免创建一个虚拟界面来解决这个问题,所以我想知道是否有更好的解决方案..?

  • 我有两个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实例。我真的不明白为什么开关会有所影响 - 我可以看到后一种方法是“更好”的,但我期望两种方法都能正确地工作,所以我想知道我是否在这里弄错了什么...

    1个回答

    13

    1) 无法避免这种情况,因为Guice在初始化自己的过滤器管道时调用所有servlet的init()方法,从而构造它们全部。如果您真的需要这样的惰性初始化逻辑,则应将其放置到servlet本身中(或使用解耦的帮助类等),具体取决于您的用例。

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

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


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接