๐ Understanding the Parent Delegation Model in JVM: A Deep Dive with Spring Boot and Tomcat ๐
Decoding the JVMโs Class Loading: A Deep Dive into the Parent Delegation Model
๐ Understanding the Parent Delegation Model in JVM: A Deep Dive with Spring Boot and Tomcat ๐
Decoding the JVMโs Class Loading: A Deep Dive into the Parent Delegation Model
If youโve faced campus recruitment interviews or worked with Java extensively, youโve likely encountered questions about the Parent Delegation Model in the Java Virtual Machine (JVM). This mechanism is a cornerstone of Javaโs class loading system, ensuring security and stability. Beyond interviews, understanding this model is crucial for working with frameworks like Spring Boot or servers like Tomcat, which customize class loading to achieve application isolation.
In this article, weโll explore the class loading process, dive into class loaders, and unravel the Parent Delegation Model. Weโll also see how itโs applied (and sometimes broken) in real-world scenarios like Tomcat and provide a Spring Boot example to illustrate custom class loading. Letโs get started! ๐
๐ Class Loading Process: A Quick Recap
Before diving into class loaders, letโs review the class loading process in the JVM, which consists of three main phases:
- Loading ๐ ๏ธ
- Retrieves the binary byte stream of a class using its fully qualified name.
- Converts the byte stream into a runtime data structure in the method area.
- Creates a
java.lang.Classobject in memory as the entry point to this data.
2. Linking ๐
- Verification: Ensures the byte stream complies with JVM specifications.
- Preparation: Allocates memory for static variables and assigns default values.
- Resolution: Converts symbolic references (e.g., class names) into direct references.
3. Initialization โก
- Executes static initializers and assigns values to static fields.
Class loading process: load -> connect(linking) -> initialize.
The connection process can be divided into three steps:
verification -> preparation -> analysis
This process transforms a .class file into a usable class in the JVM. The class loader plays a critical role in the loading phase.
๐งฉ What is a Class Loader?
A class loader is an object responsible for loading classes into the JVM. Defined by the abstract class java.lang.ClassLoader, it locates or generates the binary data for a class, typically by reading .class files from the filesystem or other sources (e.g., network, dynamic generation).
Key Points About Class Loaders
- Core Function: Loads bytecode into the JVM, creating a
Classobject. - Dynamic Loading: Classes are loaded on-demand, not all at once, saving memory.
- Resource Loading: Beyond classes, class loaders can load resources like images or configuration files.
- Array Classes: These are created directly by the JVM, not class loaders, and inherit the loader of their element type.
Every Class object holds a reference to its ClassLoader:
public class Class<T> {
private final ClassLoader classLoader;
public ClassLoader getClassLoader() { ... }
}
Built-in Class Loaders
The JVM provides three primary class loaders, forming a hierarchy:
- Bootstrap Class Loader ๐
- Implemented in C++, appears as
nullin Java. - Loads core JDK classes (e.g.,
rt.jar,resources.jar) from%JAVA_HOME%/libor paths specified by-Xbootclasspath. - No parent loader.
2. Extension Class Loader ๐ง
- Loads classes from
%JRE_HOME%/lib/extor paths injava.ext.dirs. - Parent is the Bootstrap Class Loader.
- Renamed Platform Class Loader in Java 9, handling non-core modules.
3. Application Class Loader ๐ฆ
- Loads classes from the applicationโs classpath (e.g., user-defined classes, JARs).
- Parent is the Extension/Platform Class Loader.
Custom Class Loaders
Users can create custom class loaders by extending ClassLoader. This is useful for scenarios like:
- Loading encrypted
.classfiles. - Dynamically generating classes.
- Isolating application classes (e.g., in Tomcat).

๐ณ The Parent Delegation Model
The Parent Delegation Model is the JVMโs strategy for coordinating class loading among multiple class loaders. It ensures classes are loaded efficiently and securely by delegating loading requests to parent loaders before attempting to load locally.
How It Works
When a class loader receives a request to load a class:
- Check if Loaded: The loader first checks if the class is already loaded using
findLoadedClass(). - Delegate to Parent: If not loaded, the request is forwarded to the parent class loader via
loadClass(). - Load Locally: If the parent cannot load the class (i.e.,
ClassNotFoundException), the loader attempts to load it usingfindClass().
This process continues up the hierarchy until the Bootstrap Class Loader is reached. If no loader finds the class, a ClassNotFoundException is thrown.
Hereโs the core logic from ClassLoader.loadClass():
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// Check if the class is already loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
// Delegate to parent
c = parent.loadClass(name, false);
} else {
// Use Bootstrap Class Loader
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// Parent failed to load
}
if (c == null) {
// Load locally
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
Class Loader Hierarchy
The hierarchy resembles a tree:
- Bootstrap Class Loader (C++,
null) - Extension/Platform Class Loader
- Application Class Loader
- Custom Class Loaders

Benefits of the Parent Delegation Model
- Prevents Duplicate Loading ๐ก๏ธ
- A class is loaded only once per loader, identified by its fully qualified name and loader.
- Ensures consistency across the JVM.
2. Protects Core Classes ๐
- Core classes (e.g.,
java.lang.Object) are always loaded by the Bootstrap Class Loader, preventing tampering by user-defined classes.
3. Promotes Stability ๐
- Hierarchical delegation ensures predictable and secure class loading.
Example: Exploring the Class Loader Hierarchy
Letโs write a simple program to print the class loader hierarchy in a Spring Boot application.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class ClassLoaderDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ClassLoaderDemoApplication.class, args);
}
}
@RestController
class ClassLoaderController {
@GetMapping("/classloader")
public String printClassLoaderTree() {
StringBuilder result = new StringBuilder();
ClassLoader classLoader = ClassLoaderController.class.getClassLoader();
StringBuilder indent = new StringBuilder("|--");
while (classLoader != null) {
result.append(indent).append(classLoader).append("\n");
indent.insert(0, "\t");
classLoader = classLoader.getParent();
}
result.append(indent).append("null (Bootstrap Class Loader)");
return result.toString();
}
}
Output (JDK 8):
|--sun.misc.Launcher$AppClassLoader@18b4aac2
|--sun.misc.Launcher$ExtClassLoader@53bd815b
|--null (Bootstrap Class Loader)
This confirms:
ClassLoaderControlleris loaded byAppClassLoader.- Its parent is
ExtClassLoader. - The top-level parent is the Bootstrap Class Loader (
null).
๐ ๏ธ Custom Class Loaders in Spring Boot
To demonstrate custom class loading, letโs create a custom class loader that loads encrypted .class files in a Spring Boot application. This example will respect the Parent Delegation Model by overriding findClass().
Step 1: Create an Encrypted Class File
For simplicity, weโll simulate encryption by XORing the .class file bytes with a key.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class ClassEncryptor {
public static void encryptClassFile(String inputPath, String outputPath, byte key) throws IOException {
byte[] classBytes = Files.readAllBytes(Paths.get(inputPath));
for (int i = 0; i < classBytes.length; i++) {
classBytes[i] ^= key; // Simple XOR encryption
}
Files.write(Paths.get(outputPath), classBytes);
}
public static void main(String[] args) throws IOException {
encryptClassFile("target/classes/com/example/demo/Sample.class",
"encrypted/Sample.class", (byte) 0xFF);
}
}
Step 2: Define a Sample Class
Create a simple class to encrypt:
package com.example.demo;
public class Sample {
public void sayHello() {
System.out.println("Hello from Sample!");
}
}
Step 3: Custom Class Loader
Create a custom class loader to decrypt and load the class.
package com.example.demo;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class EncryptedClassLoader extends ClassLoader {
private final String basePath;
private final byte key;
public EncryptedClassLoader(String basePath, byte key, ClassLoader parent) {
super(parent);
this.basePath = basePath;
this.key = key;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] classBytes = loadEncryptedClass(name);
return defineClass(name, classBytes, 0, classBytes.length);
} catch (IOException e) {
throw new ClassNotFoundException("Failed to load class: " + name, e);
}
}
private byte[] loadEncryptedClass(String name) throws IOException {
String classFile = name.replace('.', '/') + ".class";
byte[] encryptedBytes = Files.readAllBytes(Paths.get(basePath, classFile));
// Decrypt
for (int i = 0; i < encryptedBytes.length; i++) {
encryptedBytes[i] ^= key; // XOR decryption
}
return encryptedBytes;
}
}
Step 4: Spring Boot Integration
Use the custom class loader in a controller.
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CustomLoaderController {
@GetMapping("/load")
public String loadEncryptedClass() throws Exception {
EncryptedClassLoader loader = new EncryptedClassLoader(
"encrypted", (byte) 0xFF, getClass().getClassLoader());
Class<?> clazz = loader.loadClass("com.example.demo.Sample");
Object instance = clazz.getDeclaredConstructor().newInstance();
clazz.getMethod("sayHello").invoke(instance);
return "Loaded and executed encrypted class!";
}
}
Step 5: Run the Application
- Compile and encrypt the
Sample.classfile usingClassEncryptor. - Place the encrypted file in the
encrypteddirectory. - Start the Spring Boot application and access
/load.
Output:
Hello from Sample!
This demonstrates a custom class loader that respects the Parent Delegation Model, as it only overrides findClass().
๐จ Breaking the Parent Delegation Model
Sometimes, the Parent Delegation Model needs to be bypassed, as seen in Tomcatโs WebAppClassLoader. Tomcat breaks the model to prioritize loading classes from a web applicationโs directory (e.g., WEB-INF/classes) before delegating to parent loaders, ensuring isolation between web applications.
Why Break the Model?
- Class Isolation: Different web apps may use different versions of the same library.
- Hot Deployment: Reload classes without restarting the server.
How to Break It
To break the model, override loadClass() instead of findClass(). Hereโs a simplified example:
public class CustomBreakingClassLoader extends ClassLoader {
private final String basePath;
public CustomBreakingClassLoader(String basePath, ClassLoader parent) {
super(parent);
this.basePath = basePath;
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// Check if already loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
// Try loading locally first
c = findClass(name);
} catch (ClassNotFoundException e) {
// Delegate to parent if local load fails
c = super.loadClass(name, resolve);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
String classFile = name.replace('.', '/') + ".class";
byte[] classBytes = Files.readAllBytes(Paths.get(basePath, classFile));
return defineClass(name, classBytes, 0, classBytes.length);
} catch (IOException e) {
throw new ClassNotFoundException("Failed to load class: " + name, e);
}
}
}
This loader attempts to load classes locally before delegating, breaking the Parent Delegation Model.
Tomcatโs Approach
Tomcatโs WebAppClassLoader:
- Loads classes from
WEB-INF/classesandWEB-INF/libfirst. - Delegates to parent loaders (e.g.,
CommonClassLoader) only if the class is not found locally. - Ensures each web application has its own class namespace.

โ๏ธ Pros and Cons of the Parent Delegation Model
Pros
- Security: Prevents tampering with core Java classes.
- Efficiency: Avoids duplicate loading of classes.
- Stability: Ensures consistent class loading across applications.
Cons
- Rigidity: Canโt load local classes first, limiting flexibility.
- Complexity: Customizing requires careful handling to avoid conflicts.
๐ ๏ธ Best Practices in Spring Boot
- Leverage Built-in Loaders: Use
AppClassLoaderfor most application needs. - Custom Loaders with Care: Override
findClass()to respect the Parent Delegation Model unless breaking it is necessary. - Test Thoroughly: Ensure custom loaders handle edge cases like missing classes or resource conflicts.
- Monitor Class Loading: Use tools like VisualVM to track class loader behavior in production.
- Spring Boot Context: Be aware that Spring Bootโs
LaunchedURLClassLoaderextendsAppClassLoaderfor fat JARs, which may affect custom loader integration.
๐ Conclusion
The Parent Delegation Model is a fundamental mechanism in the JVM, ensuring secure and efficient class loading. By understanding class loaders and their hierarchy, you can harness their power in Spring Boot applications, whether sticking to the model or breaking it for specific needs like Tomcatโs web application isolation. From protecting core classes to enabling dynamic loading, this model is a key piece of Javaโs flexibility and robustness. ๐
Explore custom class loaders, experiment with Spring Boot, and dive into frameworks like Tomcat to see the Parent Delegation Model in action. Your Java applications will thank you! ๐
Happy coding! ๐ป
Thank you for your patience in reading this article! If you found this article helpful, please give it a clap ๐, bookmark it โญ, and share it with friends in need and follow me for more Spring Boot insights. Your support is my biggest motivation to continue to output technical insights!
๋ฉํ๋ฐ์ดํฐ
- post_id
- ebf31b22a4a3
- slug
- understanding-the-parent-delegation-model-in-jvm-a-deep-dive-with-spring-boot-and-tomcat-ebf31b22a4a3
- url
- https://medium.com/@umeshcapg/understanding-the-parent-delegation-model-in-jvm-a-deep-dive-with-spring-boot-and-tomcat-ebf31b22a4a3
- canonical_url
- https://medium.com/@umeshcapg/understanding-the-parent-delegation-model-in-jvm-a-deep-dive-with-spring-boot-and-tomcat-ebf31b22a4a3
- author_url
- https://medium.com/@umeshcapg
- status
- ok
- fetched_at
- 2026-07-29 03:46:03