Order of Loading Jar Files from Lib Directory

Order of loading jar files from lib directory

It's all described in Tomcat's ClassLoading HOW-TO. It's not necessarily in alphabetic order. If you observed that behaviour, it should absolutely not be relied upon if you intend to keep your webapp portable across servers. For example, Tomcat 6 "coincidentally" orders it, but Tomcat 8 does not.

Summarized, the loading order is as follows:

  1. bootstrap/system (JRE/lib, then server.loader)
  2. webapp libraries (WEB-INF/classes, then WEB-INF/lib)
  3. common libraries (common.loader, then Tomcat/lib)
  4. webapp-shared libraries (shared.loader)

If you would like to guarantee that JAR X is loaded after JAR Y, then you'd need to put JAR X in one of the places which appears later in the listing above.

There are exceptions however, which are mentioned in the tomcat docs

Lastly, the web application class loader will always delegate first for JavaEE API classes for the specifications implemented by Tomcat (Servlet, JSP, EL, WebSocket). All other class loaders in Tomcat follow the usual delegation pattern.

That means if a webapp contains any JavaEE classes (javax.*), then it will be ignored by tomcat.

For each loader, the classes are just loaded by the JVM in the order whenever they needs to be imported/executed and are not loaded yet.

Why would changing directory order of jar files in WEB-INF/lib cause a NoClassDefFoundError in Tomcat 8?

The line:

Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.geotools.referencing.datum.DefaultEllipsoid

means that the class DefaultEllipsoid is found but to be valid, there is some other class that need to be loaded but this fail. Another class is invalid.

It is this class that perhaps is duplicated with two very differents version, or one version is used for compilation, another version with different method signature at runtime.

Also, from tomcat8, the applicative jar files in WEB-INF/lib are NOT loaded according to alphabetical order anymore. I think there was a document with this on tomcat site, but for now I don't find it anymore but I found a regression bug (won't fix) on tomcat bugzilla bug 57129

This classloader stuff means that if you change some stuff on the WEB-INF/lib and restart Tomcat, then there is a bit of random class loading that make your application load one way or the other if there is duplicate jar version.

To sum up: Check the DefaultEllipsoid import and check if there is duplicate on those class. Your build also need to be cleaned to use the same version as runtime (I hope you use tools like maven to do the build)

Spring-boot inner jar files loading order? (embedded tomcat)

The jars in BOOT-INF/lib are always added to Spring Boot’s class loader in the order in which they appear in the jar. This means that if you have the same class file or resource declared in multiple jars, the same one will always win across multiple runs of your application, irrespective of operating system, Java version, etc. This holds true even if you're using Spring Boot's support for automatically unpacking certain jars at runtime.

Spring Boot also packages a BOOT-INF/classpath.idx index file in each jar that it builds. It lists all of the nested jars "in the order that they should be added to the classpath". If you unzip the jar file such that the jars in BOOT-INF/lib are then ordered by the filesystem, if you continue to use Spring Boot's JarLauncher to launch the application it will honour the order in the index.

Spring Boot contains tests, such as these, that verify the ordering of the classpath, both when launching an application using java -jar and when using java org.springframework.boot.loader.JarLauncher.

How to change order of Jars loaded from WEB-INF/lib?

As far as I know, there is no concept of alphabetical loading of jar files.

Your packaging model needs to be revisited - packaging both the patch.jar and original.jar is going to cause you grief.

Why do you need the original jar when the patch.jar contains the fixed ones?

Even if you want to retain the original.jar and patch.jar (am assuming it is complete), you can try and use the class loader hierarchy to ensure that the patch.jar is loaded first compared to original.jar always.

For e.g you can package original.jar at a shared library level with the class loading policy of parent_last and keep the patch.jar in your WEB-INF/lib.

Though i am suggesting this as an alternative, you should consider replacing orginal.jar with the patch.jar or have the patch contain all the changed files (and removing them from the original.jar)

HTH

Manglu

How to find which jars and in what order are loaded by a classloader?

The short answer is no. Classloaders are not required to expose their search logic.

However, if your classloader instance happens to be URLClassLoader or a subclass, then you do have access to the list of jars/directories, via the getURLs() method. Per the doc for this class, those URLs will be searched in order.

In practice, if you're trying to find out where a class is being loaded from, Steve's answer is probably more useful.

class loading in tomcat on demand when 2 versions of a lib are present?

From link posted by @GyroGearless

Therefore, from the perspective of a web application, class or resource loading looks in the following repositories, in this order:

•Bootstrap classes of your JVM

•/WEB-INF/classes of your web application

•/WEB-INF/lib/*.jar of your web application

•System class loader classes (described above)

•Common class loader classes (described above)

If the web application class loader is configured with <Loader delegate="true"/> then the order becomes:

•Bootstrap classes of your JVM

•System class loader classes (described above)

•Common class loader classes (described above)

•/WEB-INF/classes of your web application

•/WEB-INF/lib/*.jar of your web application

If classloader needs to load class X then once it finds it in one place it will not look for it in any other places.
Lib conflict is possible if you place one version of your dependency (say MySQL driver) to $JAVA_HOME/jre/lib/ext and another one into /WEB-INF/lib



Related Topics



Leave a reply



Submit