Unlocking Tomcat: A Deep Dive into Its Architecture and Design Patterns
This article dissects Tomcat’s mature architecture, explaining its macro and micro design, startup flow, connector and container components, lifecycle management, class‑loader hierarchy, hot‑reload mechanism, and how developers can apply the demonstrated patterns such as composite, observer, template method, and strategy in real projects.
Tomcat Architecture Overview
Tomcat is a Java HTTP server and Servlet container. It isolates network and protocol handling behind Request and Response objects, allowing frameworks such as Spring MVC to focus on business logic.
Startup Sequence
startup.sh → catalina.sh start → java -jar org.apache.catalina.startup.BootstrapThe bootstrap creates two core components:
Connector : accepts sockets, parses protocol, builds Tomcat Request / Response and adapts them to the Servlet API.
Container : manages servlet instances and dispatches the processed request.
Connector Sub‑components
EndPoint: low‑level socket listener (e.g., NioEndpoint, Nio2Endpoint, AprEndpoint). Processor: parses the application‑level protocol (HTTP/1.1, AJP, HTTP/2) and creates Tomcat request/response objects. Adapter ( CoyoteAdapter): converts Tomcat request/response to ServletRequest / ServletResponse and invokes the container pipeline.
Typical flow:
Acceptor thread accepts a Socket and creates a Channel. Poller (a Selector) detects readable channels and hands them to a SocketProcessor thread pool. SocketProcessor calls the appropriate Http11Processor (or AJP processor) to parse headers and body.
The processor builds a Tomcat Request, passes it to CoyoteAdapter, which creates a ServletRequest and invokes the container pipeline.
Container Hierarchy
Engine: top‑level container for a Tomcat instance. Host: virtual host (domain). Context: a web application. Wrapper: an individual servlet.
All containers implement the Container interface, enabling the Composite pattern so that lifecycle operations cascade from parent to children.
Lifecycle Management
Containers extend LifecycleBase, which implements Lifecycle with init(), start(), stop(), destroy(). The template method in LifecycleBase ensures that a parent’s state change triggers the same transition in its children, an application of the Observer pattern.
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
setStateInternal(LifecycleState.INITIALIZING, null, false);
initInternal();
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(..., t);
}
}Class‑Loader Architecture
Tomcat uses a custom hierarchy to isolate web applications while sharing common libraries. WebAppClassLoader: one instance per Context, breaks the parent‑delegation model by trying to load classes from /WEB‑INF/classes and /WEB‑INF/lib first, then delegating to the parent. SharedClassLoader: parent of each WebAppClassLoader, loads libraries shared across web apps (e.g., Spring). CatalinaClassLoader: loads Tomcat’s own classes, sibling to WebAppClassLoader to keep them isolated. CommonClassLoader: parent of both CatalinaClassLoader and SharedClassLoader, holds classes common to Tomcat and web apps.
Key methods in WebAppClassLoader:
public Class<?> findClass(String name) throws ClassNotFoundException {
// 1. Search WEB‑INF/classes and WEB‑INF/lib
// 2. If not found, delegate to parent (AppClassLoader)
// 3. Throw ClassNotFoundException if still missing
} public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
// 1. Check local cache
// 2. Check system cache
// 3. Try ExtClassLoader to protect JRE core classes
// 4. Search web‑app directory
// 5. Delegate to parent (AppClassLoader)
// 6. Throw if not found
}Request Mapping and Pipeline
The Mapper component maps a request URL to a specific Wrapper (servlet) by consulting the host name, context path, and servlet mappings stored in the container tree.
Tomcat processes a request through a Pipeline‑Valve chain (responsibility‑chain pattern). Each Valve implements:
public interface Valve {
void invoke(Request request, Response response);
Valve getNext();
void setNext(Valve valve);
}The container’s Pipeline maintains the chain:
public interface Pipeline {
void addValve(Valve valve);
Valve getFirst();
Valve getBasic();
void setBasic(Valve valve);
}The first Valve is invoked by CoyoteAdapter.service():
connector.getService().getContainer().getPipeline()
.getFirst().invoke(request, response);Hot Reload
Tomcat’s background thread ContainerBackgroundProcessor periodically calls backgroundProcess() on each container. Reloading a Context performs:
Stop and destroy the Context and its child Wrapper instances.
Stop and destroy listeners, filters, and the pipeline.
Dispose the web‑app class loader.
Re‑create the class loader and start the Context again.
Design Patterns Used
Composite : container tree (Engine‑Host‑Context‑Wrapper).
Observer : lifecycle events via LifecycleListener.
Template Method : LifecycleBase.init(), protocol handling abstractions ( AbstractProtocol → Http11Protocol, AjpProtocol).
Adapter : CoyoteAdapter bridges Tomcat’s internal request model to the Servlet API.
Strategy : different Processor implementations for HTTP, AJP, HTTP/2.
Responsibility Chain : Valve pipeline.
Practical Walk‑through
To trace a request:
Set a breakpoint in CoyoteAdapter.service().
Follow the call to
connector.getService().getContainer().getPipeline().getFirst().invoke().
Step through the Valve chain down to the Wrapper that invokes the servlet’s service() method.
Reference Implementation
An embedded Tomcat demo useful for debugging the source code is available at:
https://github.com/UniqueDong/tomcat-embedded
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.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
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.
