Why Tomcat Breaks Java’s Parent Delegation Model: Inside Its Class Loader Design
This article reviews Java’s default class loading mechanism, explains the parent‑delegation model, then details how Tomcat’s custom class loaders (Common, Catalina, Shared, Webapp, Jasper) intentionally deviate from that model to achieve isolation, versioning, and hot‑swap capabilities for web applications.
1. What Is the Class Loading Mechanism?
Java compiles source code into bytecode, which the JVM loads from class files into memory, verifies, parses, and initializes to create Java types that the virtual machine can use. The action of obtaining a class’s binary byte stream by its fully qualified name is performed outside the JVM by a component called a class loader .
Class and ClassLoader Relationship
Every class is associated with the class loader that loaded it, forming a unique namespace. Two classes are considered equal only if they are loaded by the same class loader; otherwise they are distinct even if they originate from the same .class file.
2. What Is the Parent Delegation Model?
From the JVM’s perspective, there are two kinds of class loaders: the Bootstrap ClassLoader (implemented in C++ and part of the VM) and all other class loaders, which are Java‑implemented and inherit from java.lang.ClassLoader. Developers typically use three system class loaders:
Bootstrap ClassLoader: Loads classes from JAVA_HOME/lib or paths specified by -Xbootclasspath.
Extension ClassLoader: Implemented by sun.misc.Launcher$ExtClassLoader, loads classes from JAVA_HOME/lib/ext or directories defined by java.ext.dirs.
Application (System) ClassLoader: Implemented by sun.misc.Launcher$AppClassLoader, loads classes from the user classpath and is returned by ClassLoader.getSystemClassLoader().
The relationship among these loaders is illustrated below:
The parent delegation model requires that, except for the top‑level Bootstrap ClassLoader, every other class loader first delegates the loading request to its parent. Only when the parent cannot find the class does the child attempt to load it itself.
Why Is This Model Needed?
Without delegation, different versions of core classes (e.g., a user‑defined java.lang.Object) could coexist, breaking the fundamental type system and causing chaotic behavior.
How Is the Model Implemented?
All logic resides in java.lang.ClassLoader.loadClass. The method checks if the class is already loaded, delegates to the parent (defaulting to the Bootstrap ClassLoader if the parent is null), and only if the parent fails does it invoke findClass to load the class itself.
Logic: first check if the class is already loaded; if not, call the parent’s loadClass . If the parent fails, catch ClassNotFoundException and invoke findClass to load the class.
3. How Can the Parent Delegation Model Be Broken?
Historically, the model has been “broken” three times:
Before JDK 1.2, when the model did not exist.
When services like JNDI need to load provider classes that reside in the application’s classpath, the JVM introduced the Thread Context ClassLoader to allow a child loader to be used by a parent.
For hot‑deployment and modularity (e.g., OSGi), where separate class loaders are created and discarded to replace modules without restarting the JVM.
4. How Does Tomcat Design Its Class Loaders?
Tomcat must isolate web applications, allow shared libraries, and support hot‑reloading of JSPs. To achieve this, it defines several custom loaders: commonLoader: Loads classes from /common/*, visible to the container and all web apps. catalinaLoader: Private to the Tomcat container, invisible to web apps. sharedLoader: Loads classes from /shared/* (merged into /lib after Tomcat 6), shared among web apps but hidden from the container. WebappClassLoader: Private to each web application, loading classes from /WEB-INF/*. JasperLoader: Loads the single class generated from a JSP file; a new instance is created when the JSP is modified, enabling hot‑swap.
Tomcat’s delegation diagram (simplified) shows that CommonClassLoader is the parent of both CatalinaClassLoader and SharedClassLoader. Each WebappClassLoader can use SharedClassLoader but remains isolated from other web apps.
Conclusion: Tomcat deliberately violates the parent delegation model; its web‑app class loader does not delegate to the parent, allowing independent loading of each application’s classes.
Summary
We have reviewed Java’s default class loading mechanism, explained the parent delegation model, examined how Tomcat’s custom class loaders break this model to provide isolation, versioning, and hot‑swap capabilities, and discussed ways to bridge the gap using the thread context class loader.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java High-Performance Architecture
Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
