我在理解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对象,即使该类未被绑定为急切的单例。 我上面提到的链接提到了在Stage.Development和Stage.Production下运行的Guice之间的区别 - 但是即使我明确地使用了Stage.Development(无论如何都是默认的),这仍然会发生。 有什么方法可以避免这种情况吗?
2)(继续1)尝试确保MyServlet首先被实例化,即使所有servlet现在急切地实例化,我在创建Injector时修改了模块(和绑定语句)的顺序,以便出现MyServlet的绑定第一。但是,我发现它仍然比其他一些绑定(非servlet类)实例化,其形式如下:
bind(MyInterface.class).to(MyClass.class).asEagerSingleton()
即使这些其他绑定稍后出现在modules / bindings顺序中。 我调查了一下,发现Guice只是实例化那些以“bind ... to ... asEagerSingleton()”形式绑定的热切单体,然后再进行“bind ... asEagerSingleton()”,所以我通过修改线解决了它: 绑定(MyServlet.class).asEagerSingleton(); 成: 绑定(MyServletDummyInterface.class)。为了(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的实例。我真的不明白为什么开关应该重要 - 我可以看到后一种方式是如何“更好”,但我希望两者都能正常工作,所以我只是想知道我是否在这里弄错了.. ?
抱歉长度,
谢谢你的帮助!
答案 0 :(得分:8)
1)没有办法避免这种情况,因为Guice在初始化自己的过滤器管道时调用所有servlet的init()
方法,从而构建它们。如果你真的需要这样的惰性初始化逻辑,你应该把它放在servlet本身(或者使用一个解耦的助手类,或者......有很多种方法,具体取决于你的用例)。
2)一般来说,Guice的模块声明绑定,没有设计成具有精确实例化顺序的引导定义。如果您需要这样定义的实例化顺序,请按所需顺序自己创建对象,并通过bind(...).toInstance(...)
绑定它们。如果你需要在自构造实例中注入,你可以使用requestInjection(...)
(如果字段/方法注入足够,那么构造函数注入会更麻烦。)
3)Guice的范围适用于绑定键,而不是绑定值,Applying Scopes描述了为什么只有你的第二个例子按预期工作。