I have a Spring based WebApp. In my application context, I have this bean defined:
<bean id="someSingleton" class="com.fake.SomeSingleton" scope="singleton"/>
I have the one Spring dispatch servlet definition and one class that has the @Controller annotation to which I auto-wired this bean, expecting Spring to only ever instantiating this class once. However, according to the following debug code, Spring is instantiating this class more than once:
private static final Semaphore SANITY_CHECK = new Semaphore(1);
public FakeSingleton(){
if(!SANITY_CHECK.tryAcquire()){
log.error("why?");
System.exit(-1);
else{
log.error("OK");
}
}
What can be the cause?
Note: I use spring 3.1.2.RELEASE
EDIT:
Thanks to the hints I was given, I found the culprit.
Apart from the DispatcherServlet, I also had a ContextLoaderListener in my web.xml. After removing it, SomeSingleton only got instantiated once.
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>FakeService</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
There are few possible reasons:
Your class is wrapped by some CGLIB proxy which causes the constructor to run twice (as opposed to
@PostConstructcallback which always runs once per bean) – once for your class and once for inheriting proxymore likely, your bean is being picked up by two contexts: main one and Spring MVC one. This is a poor practice and you should avoid it. Check out if your
SomeSingletonclass is not picked up by MVC dispatcher servlet context via some CLASSPATH scanning.BTW in such a code it’s safe to use simple
AtomicIntegerinstead ofSemaphore.