1
votes

There has been a similar question asked already at (https://groups.google.com/forum/#!searchin/google-guice/Should$20Guice-Injected$20DAO$27s$20be$20Singletons$3F/google-guice/3B8XrwB-p18/B6OF13HWRnEJ) but I don't think it has received a satisfying answer yet.

The baseline: We are using Guice in a JSF/Primefaces webapplication running on Tomcat. Persistence is handled via JPA/Hibernate.

Right now ALL our DAOs (approx. one per Entity) are annotated as @Singleton. The only reason for this seem to be performance concerns as another (non JSF but Webservice) part of the application will receive thousands of hits per seconds and our main developer believes, that constructing a DAO Singleton once and then getting it in a synchronized way is cheaper than to always inject a new instance (which is the Guice Default Scope). This goes contrary to what the Google Guice Wiki writes about Scopes: If the object is stateless and inexpensive to create, scoping is unnecessary. Leave the binding unscoped and Guice will create new instances as they're required...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?

Is the assumption correct that, with the above scenario (thousands of hits per second) using @Singleton annotated DAOs is faster and better resource wise than using Default Scope?

As we use @Singleton for our DAOs we don't inject the EntityManager directly but use an EntityManagerProvider which, as I understand it, is the correct way as the Provider is considered threadsafe which is a requirement for @Singleton. Is there a "Google approved" way to include Hibernate using DAOs in your web application?

1
I believe the Leave the binding unscoped and Guice will create new instances as they're required... comment is there to prevent developers from mixing scopes. Can you add more info about your EntitiyManager scope? How do you handle open and close of EM context? Personally, I think Singleton is in place and will perform better, cuz is little on GC and initialization. Anyway you have to know how to mix injection with different scopes and inject EntityManager as a provider, what you did, so you are all set, gj.Milan Baran
> Can you add more info about your EntitiyManager scope? What do you mean by EntityManager scope? How do you handle open and close of EM context? --- Right now we are using guice-persist's @Transactional annotation but as I learned that it is not maintained anymore we are probably going to switch to onami-persist.Michael Frank
Where did you learn that guice-persist is not maintained anymore? It seems to have recent commits.Tavian Barnes
The last non Beta Release is from March 24, 2011. Also scl's answer here: groups.google.com/forum/#!topic/google-guice/y2N1PSNmhGkMichael Frank
@MichaelFrank The last non-beta release of Guice period was on March 24, 2011.Tavian Barnes

1 Answers

3
votes

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 is the implementation of the singleton scope (it is slightly different in the released version of Guice, but the following points still stand). Every time a singleton-scoped dependency is injected anywhere, the get() method on that provider will be called to get the instance.

Double-checked locking is used so that after the singleton has been created for the first time, future calls to get() are cheap: they read a single volatile field and return.

On the other hand, using @Singleton DAOs means you have to access the EntityManager through a Provider in every method, which involves looking up the EntityManager in a HashMap in a ThreadLocal somewhere.

Conclusion: the only way to find what choice is better for performance is to benchmark both and pick the faster one. You'll probably find that both choices are fast enough, in which case you should pick the cleanest one.