Tomcat uses a custom hierarchical ClassLoader architecture to isolate web applications from each other and from Tomcat internals. Each web application deployed to the same server gets its ownDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/apache/tomcat/llms.txt
Use this file to discover all available pages before exploring further.
WebappClassLoader instance, which means two applications can use different versions of the same library without conflict — and a library upgrade in one application cannot break another.
ClassLoader Hierarchy
Tomcat creates the following loader hierarchy at startup:| ClassLoader | Source | Visible To |
|---|---|---|
| Bootstrap | JVM core + JDK modules | Everyone |
| System | $CATALINA_HOME/bin/bootstrap.jar, tomcat-juli.jar | Everyone |
| Common | $CATALINA_HOME/lib/*.jar (e.g., servlet-api.jar) | Tomcat internals + all web apps |
| Catalina (Server) | $CATALINA_HOME/lib/ (server-internal) | Tomcat internals only |
| Shared | Configured via shared.loader | All web apps (not Tomcat internals) |
| WebApp | WEB-INF/classes/, WEB-INF/lib/*.jar | That application only |
Web Application ClassLoader Behavior
TheWebappClassLoader deliberately inverts the standard Java parent-first delegation model for application-level classes. The lookup order is:
- JVM Bootstrap (Java SE APIs) — always first for security
WEB-INF/classes/— application classesWEB-INF/lib/*.jar— application JARs- Common ClassLoader (parent) — shared classes, Tomcat APIs
Common by placing its own version in WEB-INF/lib/. Jakarta EE API classes and Tomcat internal classes are always loaded from the parent (they cannot be overridden).
The parent-last behavior is specific to non-system, non-Jakarta-EE classes. The JDK’s built-in classes (
java.*, javax.* in older JDKs, jakarta.*) always come from the Bootstrap or Common loader first.Configuring Loaders via catalina.properties
The three configurable loaders are defined in$CATALINA_HOME/conf/catalina.properties:
conf/catalina.properties
| Entry | Meaning |
|---|---|
"${catalina.home}/lib" | Add a directory as a class repository |
"${catalina.home}/lib/*.jar" | Add all JARs in a directory |
"/absolute/path/mylib.jar" | Add a specific JAR |
shared.loader:
$CATALINA_BASE/shared/lib/.
Adding Libraries to Common vs. WEB-INF/lib
Choose where to place a library based on its scope:| Library type | Recommended location |
|---|---|
| Application-specific dependency | WEB-INF/lib/ |
| JDBC driver used via JNDI DataSource | $CATALINA_HOME/lib/ |
| Library shared across all deployed apps | $CATALINA_BASE/shared/lib/ |
| Library needed by Tomcat itself | $CATALINA_HOME/lib/ |
Application Isolation and ClassLoader GC
When a web application is undeployed (via the Manager app or autoDeploy), Tomcat callsContext.stop() and then discards the WebappClassLoader. The GC can then reclaim all classes loaded by that loader — provided no static references remain in parent ClassLoaders.
Memory Leaks
Memory leaks occur when code in a web application (or a library) leaves a reference to a class loaded by theWebappClassLoader in a longer-lived data structure visible to the Common ClassLoader. Common causes:
- ThreadLocal variables: If a thread in the common thread pool was used to execute application code that stored something in a
ThreadLocal, and the ThreadLocal is never cleaned up, the ClassLoader cannot be GC’d. - Static fields in shared libraries: A static
Map<Class<?>, ...>in a library placed inCommonthat stores app-loaded classes. - Driver registration: JDBC drivers registered via
DriverManager.registerDriver()fromWEB-INF/lib/stay registered in the JVM-wideDriverManager.
JreMemoryLeakPreventionListener— workarounds for JDK-level memory leaks (LDAP, DOM parsers, etc.)ThreadLocalLeakPreventionListener— renews threads in the common executor pool when a context stops, ensuring no ThreadLocal values from the old ClassLoader survive
server.xml:
JAR Scanning
At startup, Tomcat scans WEB-INF/lib JARs for:META-INF/web-fragment.xml— Jakarta EE web fragmentsMETA-INF/services/jakarta.servlet.ServletContainerInitializer— SCI registrations*.tld— Tag Library Descriptors (for JSP)
JarScanner configuration and the jarsToSkip property in catalina.properties:
conf/catalina.properties
StandardJarScanner in context.xml:
Deploying Apps
Learn how Tomcat’s ClassLoader relates to WAR deployment and hot reload.
Context Configuration
Configure WebappLoader and other Context-level class loading settings.
