Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpringMVC app... why are app contexts being initialized twice?

I've seen this basic question asked on these forums before, but none of the answers seem to solve my particular issue. Anyway, I have a small Spring webapp, consisting of a core Spring business layer, SpringMVC, and Spring-Quartz (I am also using MyBatis, although I don't believe that's relevant). All of my Spring libraries are 3.1.3

The problem is that when I deploy my app to Tomcat 6, usually the root application context and the web application context are each being initialized twice. This is evident by looking at the logs, and is also evident by the fact that my Quartz job is firing off twice when it should be firing once (that latter point is why this is not just a theoretical problem).

I thought I had my application contexts all sorted out, but clearly there must be something that I'm missing. My general approach is this:

  1. Put basic Spring configuration in spring-biz-context.xml, in the classpath (i.e. it winds up in WEB-INF/classes/com/me/config)
  2. Put Spring Quartz configuration in spring-quartz-context.xml, in the class path (i.e. it also winds up in WEB-INF/classes/com/me/config)
  3. Place an applicationContext.xml file in WEB-INF; have it simply import the above two XML files
  4. Declare a ContextLoaderListener in web.xml, so that the webapp will seek out the abovementioned applicationContext.xml file, thus initializing the root context.
  5. Declare a servlet (of type DispatcherServlet) called UsMain in web.xml
  6. Create a UsMain-servlet.xml file within WEB-INF, containing some minimal stuff just for the web application context.

Below are my config files, minus all of the XML cruft:

UsMain-servlet.xml

    <bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
</bean>

<mvc:resources mapping="/rsc/**" location="/rsc/" cache-period="31556926"/>

<mvc:annotation-driven />

<context:component-scan base-package="com.me.controllers" />

web.xml

<web-app ... version="2.5">
...

  <servlet>
<servlet-name>UsMain</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
<servlet-name>UsMain</servlet-name>
<url-pattern>/</url-pattern>
  </servlet-mapping>

<listener>  
    <listener-class>  
        org.springframework.web.context.ContextLoaderListener  
    </listener-class>  
</listener>

</web-app>

applicationContext.xml

    <import resource="classes/com/me/config/spring-biz-context.xml" />
<import resource="classes/com/me/config/spring-quartz-context.xml" />

Below are a sampling of log lines that I see twice when Tomcat starts up:

2013-11-07 05:18:27 [main] INFO  org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization started
2013-11-07 05:18:27 [main] INFO  org.springframework.web.context.support.XmlWebApplicationContext - Refreshing Root WebApplicationContext: startup date [Thu Nov 07 05:18:27 UTC 2013]; root of context hierarchy
2013-11-07 05:18:27 [main] INFO  org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/applicationContext.xml]
2013-11-07 05:18:35 [main] INFO  org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/classes/com/me/config/spring-biz-context.xml]
... bunch of stuff ...
2013-11-07 05:18:38 [main] INFO  org.springframework.web.context.support.XmlWebApplicationContext - Refreshing WebApplicationContext for namespace 'UsMain-servlet': startup date [Thu Nov 07 05:18:38 UTC 2013]; parent: Root WebApplicationContext
2013-11-07 05:18:38 [main] INFO  org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/UsMain-servlet.xml]

The one other thing which may or may not be a red herring... if I modify my code or config files in any way and then repackage the WAR file, and then stop Tomcat, copy the WAR into webapps/, and start Tomcat, the app contexts load only once (yay!) But if I restart Tomcat after that, then this problem occurs.

EDIT

As I keep exploring this issue, the "may or may not be a red herring" thing seems to be an important factor. In fact, this may be more of a question about Tomcat than about Spring.

If I delete the deployed webapp's subdirectory from within the webapps/ directory before restarting Tomcat, then the problem does not occur. If I leave the subdirectory intact before restarting Tomcat, then the problem does occur.

In other words, I package the webapp into MyApp.war, and stick that WAR into Tomcat's webapps/ directory. When Tomcat starts, it unpacks the WAR and creates a webapps/MyApp/ subdirectory. The first time, things work fine. But if I just restart Tomcat, the problem occurs. If I delete webapps/MyApp/ and then restart Tomcat, then things are again fine.

So, in a way, the problem is solved. But ideas on what is happening would be still be very helpful. To my knowledge, this is not the way Tomcat/webapps were intended to operate.

like image 782
Dave Taubler Avatar asked Nov 07 '13 05:11

Dave Taubler


1 Answers

I've been looking into this more, and it is now clear that the issue is not with Spring and its application contexts, but rather it's something that Tomcat is doing. So I will answer the question I asked with "because Tomcat is deploying the web application twice when it is restarted".

My evidence of this is that the problem never occurs if I delete my web app's deployment subdirectory from the webapps/ directory before I restart, but it always occurs if I do not delete it. Also, I added some logging to one of my "Singleton" Spring beans; when this problem occurs and the bean is created twice, each time it is loaded by a different classloader.

As to why Tomcat is doing this, I don't yet know, but that's an entirely separate question.

EDIT

Just adding that I have figured out what's up with Tomcat, just in case anyone else encounters the same issue I was having. It had to do with my attempt to deploy my WAR file as the root web application. See this URL: Apache Tomcat Configuration Reference and search for this string:

If you want to deploy a WAR file or a directory using a context path that is not related to the base file name then one of the following options must be used to prevent double-deployment:
like image 190
Dave Taubler Avatar answered Sep 26 '22 22:09

Dave Taubler