已经在(https://groups.google.com/forum/#!searchin/google-guice/Should $20Guice-Injected$20DAO$27s$20be$20Singletons$3F/google-guice/3B8XrwB-p18/B6OF13HWRnEJ)提出了类似的问题,但我认为尚未收到还没有得到满意的答案。
基线: 我们在 Tomcat 上运行的 JSF/Primefaces Web 应用程序中使用 Guice。持久性是通过 JPA/Hibernate 处理的。
现在我们所有的 DAO(大约每个实体一个)都被注释为 @Singleton。造成这种情况的唯一原因似乎是性能问题,因为应用程序的另一个部分(非 JSF,而是 Web 服务)每秒会收到数千次点击,我们的主要开发人员认为,构建一个 DAO Singleton 一次然后以同步方式获取它是比总是注入(inject)一个新实例(这是 Guice 默认范围)便宜。 这与 Google Guice Wiki 关于作用域的描述相反:如果对象是无状态的并且创建成本低廉,则不需要作用域。保留绑定(bind)的范围,Guice 将根据需要创建新实例...虽然单例可以保存对象创建(以及稍后的垃圾收集),但单例的初始化需要同步; ...
现在,“单例初始化”在这种情况下到底意味着什么?初始化是否完成一次?每次都注入(inject)吗?
在上述场景(每秒数千次点击)中,使用 @Singleton 注释的 DAO 比使用默认范围更快、更好,资源方面的假设是否正确?
当我们在 DAO 中使用 @Singleton 时,我们不会直接注入(inject) EntityManager,而是使用 EntityManagerProvider,据我了解,这是正确的方法,因为 Provider 被认为是线程安全的,这是 @Singleton 的要求。 是否有一种“Google 批准的”方式可以在您的 Web 应用程序中包含使用 DAO 的 Hibernate?
最佳答案
Although singletons save object creation (and later garbage collection), initialization of the singleton requires synchronization; ...
Now, what exactly does "initialization of the singleton" mean in this context? Is initialization done once? Everytime it is injected?
Here是单例作用域的实现(在 Guice 的发布版本中略有不同,但以下几点仍然成立)。每次在任何地方注入(inject)单例范围的依赖项时,get()
将调用该提供程序上的方法来获取实例。
使用双重检查锁定,以便在第一次创建单例后,将来调用 get()
很便宜:他们读了一个volatile
字段并返回。
另一方面,使用@Singleton
DAO 意味着您必须访问 EntityManager
通过Provider
在每种方法中,都涉及查找 EntityManager
在 HashMap
在 ThreadLocal
某处。
结论:找到性能更好的选择的唯一方法是对两者进行基准测试并选择速度更快的一个。您可能会发现这两种选择都足够快,在这种情况下您应该选择最干净的一个。
关于java - GUICE @Singleton 中正确的范围处理与默认范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27271886/