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.

Architect
Architect
Architect
Unlocking Tomcat: A Deep Dive into Its Architecture and Design Patterns

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.Bootstrap

The 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.

Connector diagram
Connector diagram

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.

Container hierarchy
Container hierarchy

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
}
Class loader hierarchy
Class loader hierarchy

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 ( AbstractProtocolHttp11Protocol, 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
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Design PatternsJavaarchitectureMicroservicesClass LoaderWeb serverTomcat
Architect
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.