โ† Back to list

๐Ÿ” 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

Umesh Kumar Yadav ยท 2025-06-07 16:41 ยท 7 claps ยท 7.9 min read paywalled
#java #spring-boot #delegation #custom-classloader #class-loader
Open on Medium โ†—
Wiki topics: ๐Ÿ’ป ยท Programming

๐Ÿ” 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:

  1. 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.Class object 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 Class object.
  • 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:

  1. Bootstrap Class Loader ๐ŸŒŸ
  • Implemented in C++, appears as null in Java.
  • Loads core JDK classes (e.g., rt.jar, resources.jar) from %JAVA_HOME%/lib or paths specified by -Xbootclasspath.
  • No parent loader.

2. Extension Class Loader ๐Ÿ”ง

  • Loads classes from %JRE_HOME%/lib/ext or paths in java.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 .class files.
  • 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:

  1. Check if Loaded: The loader first checks if the class is already loaded using findLoadedClass().
  2. Delegate to Parent: If not loaded, the request is forwarded to the parent class loader via loadClass().
  3. Load Locally: If the parent cannot load the class (i.e., ClassNotFoundException), the loader attempts to load it using findClass().

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

  1. 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:

  • ClassLoaderController is loaded by AppClassLoader.
  • 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

  1. Compile and encrypt the Sample.class file using ClassEncryptor.
  2. Place the encrypted file in the encrypted directory.
  3. 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/classes and WEB-INF/lib first.
  • 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

  1. Leverage Built-in Loaders: Use AppClassLoader for most application needs.
  2. Custom Loaders with Care: Override findClass() to respect the Parent Delegation Model unless breaking it is necessary.
  3. Test Thoroughly: Ensure custom loaders handle edge cases like missing classes or resource conflicts.
  4. Monitor Class Loading: Use tools like VisualVM to track class loader behavior in production.
  5. Spring Boot Context: Be aware that Spring Bootโ€™s LaunchedURLClassLoader extends AppClassLoader for 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