I am completely confused over how the class loading happens in tomcat. So please bear with me if my question sounds stupid.
We deploy multiple spring webapps on single tomcat server. To reduce the memory footprint, we thought of having spring, hibernate and database driver jars in tomcat lib folder so that those are shared by all webapps.
I started first by marking spring dependencies as provided
and copied those jars to tomcat lib. But on server startup I started getting multiple ClassNotFoundErrors
, like for commons-logging
, commons-fileupload
, jackson
, so I had to move these jars as well to tomcat lib.
But then this started feeling fishy. What if in future I add another spring dependency to my project, say spring-data-cassandra. Would I need to move it's dependent jars as well? This might be unending. Also I might get CNF errors at runtime.
I tried to follow this link and brought back spring-context and spring-web back to application war. But it didn't work, got ClassNotFound on some class during WebApplicationIntializer
initialization. I tried to understand the order of classes getting loaded in tomcat, but could not understand much.
Then I found a complete different explanation for JDBC driver loading which kinda contradicts to all other explanations and left me completely confused.
As I read more, I think it is not a right approach to move spring jars to tomcat lib, but still haven't got a good reasoning. And then why JDBC driver works? Can someone please explain? Also does classloader for each webapp creates a copy of each class?
Edit 1: I came to know that few dependencies are optional
in spring jars, and will be required if are in use in my webapp. So spring-web depends on jackson
libraries but is optional for my app. So I need to find out which all jars are required for my project and are also required by spring, those jars need to be moved to tomcat lib.
A web app's WEB-INF\lib folder and the Tomcat \lib directories are the best places to deploy JAR files in Tomcat.
home}/lib folders (which by default are equal to the lib folder of your Tomcat installation) are loaded by the common classloader. Classes in the WEB-INF/classes and jars in the WEB-INF/lib folder (or WAR archive) are loaded by the web application class loader.
You can not deploy Jar to tomcat and expect it to load your web application. War has its own directory and file structure defined which is read by tomcat and load the application accordingly. It can not understand jar file as web application and run it.
Place it in /code/jars or /code/jars/static on the package file system on the IS server . On designer, you have to import the jars to your build path during compilation.
I will try to explain what I know.
When you deploy a WAR on your tomcat, the class loading will happen this way :
What happen in your case is that spring also have a lot of dependencies, if you package it in your war, its dependencies would have been packaged as well and everything would have worked fine. But since you defined spring as provided, all its dependencies are considered provided as well, and when you put it in /lib folder, spring is accessible, but its dependencies are not.
What you need to do is put all spring dependencies and the dependencies of dependencies (etc.) in lib folder as well. Another solution is to define an intermediary WAR in your classloading hierarchy which will contains all your common libs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With