Background
We have several webapps running on Tomcat 7.0.x (on Linux). For historical reasons, we have populated the “Common” lib (i.e. $CATALINA_HOME/lib) with many application jars. These jars include Spring, Jackson, and our own persistence-layer jars.
As we deploy new persistence-layer jars, we are embroiled in a classpath hell: some jars are OK in ~/webapps/foo/WEB-INF/lib, but some must be excluded and placed in Common. Recent adventures show that some may have to be in both places.
Our local (Windows) build is similarly messy: we have one folder filled with jars. We build with Eclipse (not Gradle, Ant, etc) and do not have an explicit list of jars used by the web applications. The Linux build does use Ant, but semi-selectively globs jars into the WAR files.
Question
I would like to white-board a strategy on how to extricate ourselves from this predicament. One approach is listed below, but I would appreciate any refinements, or alternative approaches.
The goal is to correct the deploy process, not the local build.
Strategy
On local machine, use Gradle to compile each web application:
- add compile-time dependencies until compilation is OK
- locate Gradle’s local cache (or observe output) to find transitive run-time dependencies
- add all jars to ~/WEB-INF/lib for the web app, with explicit references in the formal Ant build
- deploy into a fresh, pristine Tomcat install
- observe startup logs for any “ClassNotFound” exceptions, both for 3rd-party libraries and our application libraries
- add these libraries to the formal Ant build
- perform regression QA tests on application and monitor for “ClassNotFound”
2
In my experience building applications using Maven for Tomcat 6 and Tomcat 7, I never needed to deploy jars explicitly to Tomcat’s common lib directory.
Take a look at this post: https://stackoverflow.com/questions/267953/managing-libraries-in-tomcat
Answers there indicate that conflicts may arise between classes in the shared common lib folder, and those in each web application, as each web application may have dependencies of differing versions.
Also, according to the Tomcat page you linked to for Common class loader libraries: “Normally, application classes should NOT be placed here”.
For example, if you had log4j-1.2.15.jar in the commons/lib directory, and log4j-1.2.17.jar in your application lib dir, Tomcat may try to load 1.2.15, while your application was written to use 1.2.17, which can lead to ClassNotFoundExceptions, and potentially other exceptions.
I’d recommend only placing libraries that Tomcat needs for itself into the common lib directory, and let each application context load its own dependencies.
If you use Maven (and configure the project correctly), you should not need to manually move any jars around. Gradle may have similar functionality.