Enno Shioji
Enno Shioji

Reputation: 26882

What can cause Spring IoC instantiate more than one instance of a singleton bean per WebApp?

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>

Upvotes: 1

Views: 472

Answers (2)

Tomasz Nurkiewicz
Tomasz Nurkiewicz

Reputation: 340733

There are few possible reasons:

  • Your class is wrapped by some CGLIB proxy which causes the constructor to run twice (as opposed to @PostConstruct callback which always runs once per bean) - once for your class and once for inheriting proxy

  • more 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 SomeSingleton class is not picked up by MVC dispatcher servlet context via some CLASSPATH scanning.

BTW in such a code it's safe to use simple AtomicInteger instead of Semaphore.

Upvotes: 2

bmargulies
bmargulies

Reputation: 100013

A singleton is once per context, not once-per-heat-death-of-the-universe.

Turn on logging and see why/if the entire app context is being created more than once.

Upvotes: 1

Related Questions