Dive deep into Java Class loader Part 1
Class loader in Java is a useful concept in many situations. Understanding and manipulating it well is key to using many tools effectively, such as Tomcat, Spring, and Maven. This post will discuss the concept of class loaders in Java.
Note: This post covers class loaders only up to Java 8. Class loader in higher versions of Java may change.
Compile and run Java
Compile
During compilation, every Java file is compiled into bytecode and stored in a Class file. The Class file contains the Bytecode that the JVM can execute, as well as Metadata about the Class.
JAR file (Java Archive file): is a file that archives all Class files, Metadata, and resources (text, images, etc.) of a project in the ZIP format.
Classpath: a list of directories and JAR files that the JVM searches to find Class files.
JVM
The JVM's first step is to load Classes. It does this through the Bootstrap Class Loader, which is part of the JVM code. The Bootstrap Class Loader loads all of the core Java Classes such as String, Object and built-in ClassLoader such as Extension Class Loader and Application Class Loader. After that, the JVM will load the Main Class of the project and ask the Extension Class Loader and Application Class Loader to load any new classes that are needed.
Class loader
Each class loader is responsible for loading a kind of Classpath. When the Class loader load class files it reads the Class files into Memory, parse the Metadata inside the Class files, and converts the Metadata to Class Objects, which are then stored in Heap Memory.
Hierarchy
All Class loaders in Java, except for the Bootstrap Class Loader, are built in a one-to-many child-parent relationship. This creates a tree-like hierarchy with the Bootstrap Class Loader at the root. There are two ways Class loader can handle loadClass()
method:
Parent-first (delegation model): it first asks its parent Class loader and then tries to find the Class itself.
Self-first (child-first): it first tries to find the Class itself, and only then does it ask its parent to load the Class.
For security reasons, the parent-first strategy is preferred. This is because it prevents Class loaders from loading malicious Classes that override Classes already loaded by higher-level Class loaders.
The barebones Java runtime comes with three built-in Class loaders:
Bootstrap Class Loader
Extension Class Loader
Application Class Loader
Bootstrap Class Loader
Unlike other Class loaders, the Bootstrap Class Loader is written in native code inside JVM. This is because the Bootstrap Class Loader is the highest in the hierarchy. If it were written in Java, it would be a Class and would need a Class loader to load it. However, there is no higher Class loader than the Bootstrap Class Loader, so it cannot be loaded in this way.
Bootstrap Class Loader response for $JAVA_HOME/jre/lib
Classpath.
Note: Since the Bootstrap Class Loader is not a Class, calling the getClassLoader()
method on a Class loaded by the Bootstrap Class Loader will return null
.
String.class.getClassLoader(); // null
Extension Class Loader
The Extension Class Loader is a child of the Bootstrap Class Loader and is responsible for loading Classes from the extension Classpath, which is typically stored in $JAVA_HOME/lib/ext
.
Connection.class.getClassLoader();
Application Class Loader
The Application Class Loader is a child of the Extension Class Loader and is responsible for loading all of the Class files in the project.
public class Main {
public static void main(String[] args) {
Main.class.getClassLoader();
}
}
Reference
[1] Inside Java 2 Platform Security: Architecture, API Design, and Implementation, Second Edition