I have a tomcat server with two webapps (foo and bar) that have an identical deployment war. The deployment uses the standard Spring/Hibernate setup. I assumed that these two webapps would start up and run completely independent of one another, but that is not the case - webapp foo loads normally, but webapp bar has some strange behavior - it's as if it is using some of the same beans from webapp foo. For example, when bar starts up (the 2nd weba开发者_Python百科pp to start), c3p0 complains that it is already registered - presumably in webapp foo. Again, I'm trying to make the two webapps completely independent, such that there should be no way for the two c3p0/hibernateSessionFactory beans to know about one another.
In doing some research, I've been led to believe that the same Spring root WebApplicationContext is being used in both webapps. If that is the case, how can I make each webapp (on the same tomcat server) completely independent of one another? Is there anything else that could be causing this problem?
Relevant excerpts from web.xml:
<web-app>
<context-param>
<param-name>org.hibernate.tags.sessionFactory</param-name>
<param-value>hibernate/SessionFactory</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context/*Context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>fooServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
</web-app>
I have a suspision. Isn't class-loading the root of your problem?
I guess the direct reason for your problem is that some Spring class is loaded once and shared between these two WARs. I don't know the exact name of the class, but Spring needs to store some shared information (at least the reference to the application context) in some static field. Then when two WARs see the same copy of the class, then both applications see the same state of this static field. I guess in your setup Spring creates only one application context (when the second one should be created, Spring finds an existing application context and uses it instead).
I see potential two reasons for such a problem:
- either this is a class-loading issue. I am not that into tomcat and have no clue how and if you can configure that, but typically in JavaEE application servers there's some way to configure class-loading for WARs.
- or this is a kind of memory leak. Maybe the class (and its static field) is re-used from some previous deployment (unlikely, your description tends to suggest you encounter the problem on a fresh instance of tomcat). You can rule out this possibility by making sure the problem appears just after your (re)started tomcat.
UPDATE: If this is about class-loading, I would try to figure out which class (and its static field) is causing problems. This is probably not your class but some 3rd-party library class you use in your application. After reading http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html you can see that Tomcat uses different unrelated class loaders for each application. However both of them share the parent class loaders which they delegate to if they don't know the class. Again, I don't know your exact setup and some Tomcat peculiarities, but... Isn't it possible in Tomcat to put some library (JAR), like c3p0 or Spring, in some common 'lib' folder (the docs says $CATALINA_HOME/lib)? In such a case the classes from these JARs are loaded using parent class loader (the one called 'Common' in the tomcat docs). That implies they are loaded only once.
To make the story short, I guess the reason is that one of the JARs in your $CATALINA_HOME/lib has some class which relies heavily on some static fields. Tomcat policy to load the JARs using Common class loader results in all applications sharing the state of these static fields.
Have I told you this is only a suspicion and guessing?
精彩评论