How are singletons handled in a web application?
From what I understand, a singleton is basically when you have a private member that represents the object you want to have a single instance for. Then in the constructor you initialize the member object.
All refe开发者_如何学运维rences for this object are done via a public property, and the public property just references the private member that has already been instantiated.
Now in a web application, how does this work? Does a single instance just hang around in the container (say tomcat) until tomcat is shutdown?
If your execution environment uses multiple class loaders, then you get one singleton per instance of your class. If your singleton class is loaded into different class loaders, then it's actually two distinct classes and then there will be two "singleton" instances.
You can find some info on the Tomcat class loaders in the documentation.
A distinction should be made between the Singleton pattern, and its implementation. Most if not all common Singleton implementations suffer from the mentioned problems with classloading as well as serialization, thread safety etc. See https://www.securecoding.cert.org/confluence/display/java/MSC07-J.+Prevent+multiple+instantiations+of+singleton+objects for a quite thorough overview.
However, the Singleton pattern in its broadest sense can be any service guaranteed to be unique within a certain context. The uniqueness of a Singleton can only be specified relative to a given scope like a classloader, JVM, container or cluster; the level of uniqueness depends on the implementation, which should be chosen based on the application's requirements.
Two very common requirements leading to the use of Singletons are dependency injection (c.q. using a factory) and in-memory caching. In both cases there are good frameworks that hide the Singleton aspect from the client and offer a sufficient level of uniqueness within for instance an enterprise application container. For dependency injection Spring, Guice or Pico come to mind. For caching I know Ehcache as leading solution, but there are certainly more out there. (fun trivia: The name 'ehcache' is a palindrome)
In general, use of Singletons is 'frowned upon', and seen as an anti-pattern. On the other hand, services like dependency injection and caching require uniqueness to work. So we are fooling ourselves a bit if we proclaim to be anti-Singleton and at the same time use Spring or Ehcache or the like.
The fear of Singletons in my opinion stems from the many poor implementations that are possible, and abundant. And even if the Singleton implementation itself is 'safe', calling it directly (via static access) throughout the application leads to tight coupling and poor testability.
An improvement you can make if you have a Singleton factory in your application, is to refactor its clients so that they don't call the factory whenever they need a dependency, but provide a private field and a public setter allowing the dependency to be injected. You can then centralize the initialization of the clients, maybe in the same factory, and leave the client code clean, loosely coupled and testable (you can inject mock dependencies now). This could also be a first step towards introducing a dependency injection framework like Spring.
I hope somewhere in this rather long and rambling post I helped answer your question! (-;
Now in a web application, how does this work? Does a single instance just hang around in the container (say tomcat) until tomcat is shutdown?
@Greg's answer explains that there may be a different instances of the singleton class (actually different classes from the JVM's perspective) if each webapp container in TomCat has its own classloader.
Either way, the (GC) lifetime of a singleton will be the lifetime of the respective classloaders. In practice though, it is easy for references to a classloader to leak, resulting in the singleton living until the JVM exits.
This is one of the reasons that conventional singletons are problematic in web applications. It is better to use "container scoped" instances; e.g. as supported by Spring and other IoC frameworks.
Yes, there's a singleton pattern, which works as you describe. It's problematic and comes with caveats as mentioned by Stephen C above. If you need single instance data your best option is to have it built by a spring container (or other containers that support this), which will handle the instantiation (which is much more problematic than you might think).
If you must roll your own, read up thoroughly on the double-checked locking idiom and the issues that come with it to understand the issues that can come up with singleton instantiation. If your instantiation is non-trivial it's actually very easy to get multiple instances or race conditions in instantiation. I've done it myself. In production (but it was a long time ago ;) )
精彩评论