Whenever a new JVM is started the bootstrap classloader is responsible to load key Java classes (from
java.lang package) and other runtime classes to the memory first. The bootstrap classloader is a parent of all other classloaders. Consequently, it is the only one without a parent.
Next comes the extension classloader. It has the bootstrap classloader as parent and is responsible for loading classes from all
.jar files kept in the
java.ext.dirs path–these are available regardless of the JVM’s classpath.
The third and most important classloader from a developer’s perspective is the system classpath classloader, which is an immediate child of the extension classloader. It loads classes from directories and jar files specified by the
CLASSPATH environment variable,
java.class.path system property or
-classpath command line option.
Note that the classloader hierarchy is not an inheritance hierarchy, but a delegation hierarchy. Most classloaders delegate finding classes and resources to their parent before searching their own classpath. If the parent classloader cannot find a class or resource, only then does the classloader attempt to find them locally. In effect, a classloader is responsible for loading only the classes not available to the parent; classes loaded by a classloader higher in the hierarchy cannot refer to classes available lower in the hierarchy.
The classloader delegation behavior is motivated by the need to avoid loading the same class several times. Back in 1995, the chief application of the Java platform was thought to be web applets living in the client (browser). As connections at that time were slow, it was important to load the application lazily over the network. Classloaders enabled this behavior by abstracting away how each class was loaded. All the bells and whistles came later.
However, history has shown that Java is much more useful on the server side, and in Java EE, the order of the lookups is often reversed: a classloader may try to find classes locally before going to the parent.
Java EE delegation model
Here’s a typical view of an application container’s classloaders hierarchy: there is a classloader of the container itself, every EAR module has its own classloader and every WAR has its own classloader.
The Java Servlet specification recommends that a web module’s classloader look in the local classloader before delegating to its parent–the parent classloader is only asked for resources and classes not found in the module.
In some application containers this recommendation is followed, but in others the web module’s classloader is configured to follow the same delegation model as other classloaders–so it is advisable to consult the documentation of the application container that you use.
The reason for reversing the ordering between local and delegated lookups is that application containers ship with lots of libraries with their own release cycles that might not fit application developers. The classical example is the log4j library–often one version of it is shipped with the container and different versions bundled with applications.
“The reversed behavior of web module classloader has caused more problems with classloaders than anything else… ever.”
- JEVGENI KABANOV
Now, let’s take a look at several common classloading problems that we might encounter and provide possible solutions.