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.
I will try to explain what I know.
When you deploy a WAR on your tomcat, the class loading will happen this way :
look for the class to load in your WAR classLoader
if not found move to parent (tomcat /lib folder)
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 prefer to create this type of thin WAR, one solution would be to first gather all runtime/provided dependencies and then copy them explicitly under Tomcat's common (or shared) library directory:
If under a Maven project, gather everything (including transitive dependencies) under target/dependency:
mvn dependency:copy-dependencies -DincludeScope=runtime
mvn dependency:copy-dependencies -DincludeScope=provided
Afterwards, copy to library. For example:
cp target/dependency/*.jar /usr/local/tomcat/lib/
Related
I have a maven Spring Boot web application with quite a few (transitive) dependencies.
There are .jar files in the WEB-INF/lib folder inside the built .war.
For example:
hibernate-jpa-2.1-api-1.0.0.Final.jar
javax.persistence-2.1.0.jar
Both of these contain a class called javax/persistence/JoinColumn.class (with different file sizes).
At runtime, which "version" is going to be referenced when I use it in the code?
Can this type of dependency cause problems later?
To answer your question:
You don't know.
Yes, this will cause problems later.
For a more elaborate answer, check https://stackoverflow.com/a/5474838/7430994
I've built a basic Java Web Project using Netbeaans, which uses Maven.
The issue is, in my 'dependencies' I see 'javaee-web-api-6.0.jar'. However, when I build the project, in the .war file I don't see this .jar file included anywhere.
Am I missing something, or is there any extra step that I need to take to have all the dependencies be included in the .jar?
Servlet API dependencies should never be in the resulting war file. It is a dependency that is provided by your container. Having it in the war file would only result in a bunch of classloader issues. Most containers would ignore the jar file anyway, if it was present inside the war.
Check the scope of javaee-web-api-6.0.jar dependency. If its provided then it will not be bundled into the resultant war.
javaee-api-6.0.jar and servlet-api-3.jar These jars are already provided by Tomcat(assuming using tomact). To verify this look in <TOMCAT_HOME>\lib to see that these jars are already there.
So I am working on a project whereby we needed to create a custom Tomcat Realm implementation to read authentication credentials from a mongo backed datastore.
This has been pretty painless, but the implementation we have come up with has several dependencies on external libs i.e. scala libs, the java mongo-db driver, spring, salat (a mongodb ORM) etc....
Now in order for Tomcat to use this Realm we must deploy our Jar (and all the dependent jars) to tomcats lib folder.
Being pretty new to Java, I have no idea how much of an issue this is, but it doesn't seem nice to me. So really, my question is what issues would I have with dumping a load of JARs into Tomcats lib directory?
Cheers, Chris.
Most likely dependencies will become a problem. All JARs you place in tomcat/lib are visible to the WARs you deploy at a later time. I suppose your Realm implementation is the base for one or more web applications.
Let's say your Realm depends on Spring 2.0 and you're required to place those libs in tomcat/lib and afterwords you deploy a WAR using Spring 3.0. The WAR will see all classes available in tomcat/lib - the Spring 2.0 classes. So your WAR ships the 3.0 classes in WEB-INF/lib, at runtime it can see the Spring 2.0 libs in tomcat/lib as well as its own Spring 3.0 libs in WEB-INF lib. This is going to cause trouble...
I'm not aware of a simple solution for this, maybe you should have a look at OSGI and Tomcat integration. No question, it won't make life easier...
Resin java server has a neat feature they call pomegranate ( http://www.caucho.com/projects/pomegranate/ ) which allows to just put various jar dependencies in server's directory (project-jars/) and then it loads them for a web-app from its pom.xml file.
Question is: how should I put the jars to resin's project-jars ? (just copying them doesn't work)
Details:
I have a working project with maven, with all dependencies configured in
projects pom.xml file. I can build a webapp war etc.
I copied the jar files to resin's project-jars/ as they were generated by maven for this particular web-app.
When I deploy the war, resin spots pom.xml and tries to resolve
dependencies; unfortunately it cannot find any artifacts in its
repository (project-jars).
I suppose this is because all the jars I have put there do not have
META-INF/maven/pom.xml files packed in them. They are just normal jars
like those downloaded by maven.
On pomegranate website they say resin scans project-jars for jars with pom.xml files, to determine their versions.
How should I create jars with pom.xml files included?
Or should I manually copy the foo-bar-1.0.pom files from the repository on my devel
machine to the resin's project-jars directory? (which kind of beats the purpose of all the auto-magic)
Thanks for answer,
Best regards
Horace
My understanding of the Pomegranate Draft specification is that:
Servlet containers can use pomegranate as an extension to the WEB-INF/lib with the following benefits:
Shared .jar files in a common repository, simplifying management and reducing .war sizes
Library dependency resolution, including the ability to handle sub-module incompatibilities
Familiar Maven pom.xml files, to take advantage of current development practices.
Optional integration with Servlet web-app containers
Optional integration with Java CanDI (JSR-299) managers
[...]
The web-app may contain an optional WEB-INF/pom.xml declaring the web-app's own dependencies.
So I guess the idea is to mark the dependencies as "provided" in the war pom.xml and to add them in WEB-INF/pom.xml for a deployment on Resin. I've not tested this though, so I might be wrong.
Actually, this pomegranate looks interesting but I don't get it entirely for now. While I understand its benefits, it seems to make the WAR not portable which is a big drawback. I'll dig it a bit further...
(EDIT: I'm putting an answer to a comment from the OP below)
To be honest, I don't find the spec draft very clear. However, I found this pomegranate modules post on Caucho's blog that details a bit more how to get it working for a webapp:
Pomegranate is designed to solve the
module versioning and classloader
issues from an enterprise-application
perspective. Although we’re doing a
bit of classloader magic behind the
scenes, the developer perspective is
fairly simple and clean:
remove jars from your .war
drop them in Resin’s project-jars directory
declare jar dependencies in Maven pom files
import them to your web-app with WEB-INF/pom.xml or in your
resin-web.xml
At least, I understand these steps and they answer your question: you have to drop the jars manually in Resin's project-jars directory. That's not what I was expecting but I think that I was misunderstanding what pomegranate is all about. If I'm not wrong, pomegranate is a kind of alternative to OSGI, it is about module bundling and classloading voodoo. It uses Maven's conventions to describe dependencies but it's not about dependencies management.
I would like to use the spring framework within an EJB3 project. In detail I would like to use the JDBC template class which should be instantinated from a given data source. When I put the spring.jar to my Jboss lib directoy everything is working fine. But when I put the JAR inside my EAR only there seems to be external dependencies from JDbcTemplate to other libraries. EARs/EJBs classloader try to instantinate the JdbcTemplate and shows me that he can not load the class because of external dependencies. It does not show me which additional JARs I have to put in.
Question: Does some body know which addtional JARs I have to include or even how I can search for depending JARs with external tool. I remember there is a tool which can do this, but I do not know its name anymore. I think something like jarjar etc.
Could anyone help please? Thank you.
This smells like an EAR config problem not an Spring problem. Are you sure that the jar is in the EJB's classpath? You might want to check the MANIFEST.MF file of the EJB's jar to verify this.