Tomcat Architecture Overview: Connectors, Containers, and Lifecycle

This article provides a detailed overview of Tomcat’s backend architecture, explaining its core components such as the server, service, connector, lifecycle management, protocol handler, endpoint, processor, adapter, and container hierarchy, and includes code examples illustrating the request‑response flow.

Top Architect
Top Architect
Top Architect
Tomcat Architecture Overview: Connectors, Containers, and Lifecycle

This article presents a comprehensive description of the internal architecture of Apache Tomcat, focusing on how it processes HTTP requests and manages servlet lifecycles.

Core functions include handling socket connections, converting network byte streams into Request and Response objects, loading and managing Servlets, and processing incoming requests.

Tomcat supports several I/O models (NIO, NIO2, APR) and application‑layer protocols (HTTP/1.1, AJP, HTTP/2.0). At the top level, a Server contains multiple Service instances; each Service has one or more Connector objects and a Container. Connectors and containers communicate via ServletRequest and ServletResponse.

The framework uses design patterns such as Composite, Template Method, Observer, and a skeletal abstract class LifeCycleBean that implements the LifeCycle interface. Subclasses implement their own init, start, and stop methods.

Connector responsibilities are broken down into network listening, request acceptance, byte‑stream reading, protocol parsing, conversion to Tomcat request/response objects, adaptation to servlet request/response, and finally writing the response back to the client.

The ProtocolHandler chain consists of Endpoint, Processor, and Adapter components. The Endpoint listens on a socket and creates a SocketProcessor for each connection. The Processor (e.g., Http11Processor, AjpProcessor) parses the protocol and builds Tomcat request objects, which the Adapter (e.g., CoyoteAdapter) converts to ServletRequest and invokes the servlet service method.

The Container hierarchy follows Engine → Host → Context → Wrapper → Servlet. Each level inherits from ContainerBase and implements the Container interface, allowing independent lifecycle management. Requests flow through a Pipeline‑Valve chain, where each Valve can process or modify the request before passing it to the next.

Example of invoking the container pipeline:

1 // Calling the container
2 connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);

Excerpt from StandardWrapperValve showing how the filter chain and servlet service are invoked:

final class StandardWrapperValve extends ValveBase {
    @Override
    public final void invoke(Request request, Response response) throws IOException, ServletException {
        // ...
        ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
        // Call the filter chain for this request
        // NOTE: This also calls the servlet's service() method
        Container container = this.container;
        try {
            if ((servlet != null) && (filterChain != null)) {
                if (context.getSwallowOutput()) {
                    try {
                        SystemLogHandler.startCapture();
                        if (request.isAsyncDispatching()) {
                            request.getAsyncContextInternal().doInternalDispatch();
                        } else {
                            // dofilter
                            filterChain.doFilter(request.getRequest(), response.getResponse());
                        }
                    } finally {
                        String log = SystemLogHandler.stopCapture();
                        if (log != null && log.length() > 0) {
                            context.getLogger().info(log);
                        }
                    }
                } else {
                    if (request.isAsyncDispatching()) {
                        request.getAsyncContextInternal().doInternalDispatch();
                    } else {
                        // dofilter
                        filterChain.doFilter(request.getRequest(), response.getResponse());
                    }
                }
            } else {
                if (request.isAsyncDispatching()) {
                    request.getAsyncContextInternal().doInternalDispatch();
                } else {
                    // dofilter
                    filterChain.doFilter(request.getRequest(), response.getResponse());
                }
            }
        } catch () {
            // ...
        }
    }
}

Overall, the article explains how Tomcat’s modular components collaborate to transform raw network data into servlet‑compatible requests, manage their lifecycles, and deliver responses, providing both conceptual diagrams and concrete code snippets for deeper understanding.

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.

JavaServletTomcat
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

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.