In‑Depth Overview of Tomcat Architecture, Components, and Lifecycle
This article provides a comprehensive technical guide to Apache Tomcat, covering its servlet container architecture, core components such as Server, Service, Engine, Host, and Context, lifecycle management, request processing pipeline, connector types, JSP handling, asynchronous servlet support, and related code examples.
Apache Tomcat is an open‑source Java web server that implements key Java EE specifications such as Servlet, JSP, JSTL, and WebSocket. It serves as a lightweight servlet container, while other Java EE features (EJB, JPA, JMS, etc.) require additional implementations.
Tomcat Component Overview
Server – the top‑level container managing multiple Services and listening on the shutdown port.
Service – groups a single Engine with its Connectors.
Engine (Catalina) – the top‑level servlet container handling virtual hosts.
Host – represents a virtual host that creates Contexts for each web application.
Context – the web‑application context that holds Wrappers for individual Servlets.
Wrapper – the lowest‑level container that creates, invokes, and destroys a Servlet instance.
Additional components include Loader (class loading), Realm (authentication/authorization), JMX (monitoring), Jasper (JSP engine), Session management, Pipeline with Valve chain, Naming (JNDI), and Connector (HTTP/AJP communication).
Lifecycle Management
Tomcat defines twelve lifecycle states (New, Initializing, Initialized, Starting, Started, Stopping, Stopped, Destroying, Destroyed, Failed, etc.). Each component implements methods such as initInternal , startInternal , stopInternal , and destroyInternal to transition between states. Event listeners can be registered (e.g., in server.xml ) to react to state changes.
Servlet Lifecycle
Request arrives and is mapped to a Servlet.
If the Servlet instance does not exist, Tomcat loads, instantiates, and calls init() .
Tomcat creates Request and Response objects and invokes service() (which delegates to doGet , doPost , etc.).
The Servlet processes business logic and writes the result to the response.
When the Servlet is no longer needed (e.g., server shutdown), Tomcat calls destroy() .
JSP Lifecycle
Compilation – JSP source is compiled into a Servlet class by Jasper.
Initialization – the generated Servlet is loaded, instantiated, and init() is called.
Execution – the Servlet’s _jspService() method processes each request.
Destruction – destroy() is invoked when the JSP is unloaded.
JSP elements include scriptlets ( <% … %> ), declarations ( <%! … %> ), expressions ( <%= … %> ), directives ( <%@ … %> ), actions ( <jsp:… /> ), and implicit objects (request, response, session, etc.).
Pipeline and Valve
The request passes through a Pipeline where each Valve can process or modify the request/response. The final basic valve invokes the next container in the hierarchy. Typical basic valves are StandardEngineValve , StandardHostValve , StandardContextValve , and StandardWrapperValve .
Connector Types
Tomcat supports three connector implementations, selectable in server.xml :
BIO (JIO) – Java I/O, blocking sockets.
NIO – Java NIO, non‑blocking with I/O multiplexing (selector).
APR – Apache Portable Runtime, native I/O via JNI for higher performance.
Each connector differs in support for polling, thread handling, and read/write blocking behavior.
Asynchronous Servlet Support
Async servlets allow a request thread to be released while business logic runs in a separate thread. The servlet calls request.startAsync() , obtains an AsyncContext , and later completes the response via asyncContext.complete() . Async events include onStartAsync , onComplete , onError , and onTimeout .
Comet (Long‑Polling) Support
Tomcat can implement Comet by having a servlet implement CometProcessor with callbacks begin() , read() , end() , and error() . This enables server‑push style communication before WebSocket became standard.
List<Future<Void>> results = new ArrayList<Future<Void>>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
boolean fail = false;
for (Future<Void> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
fail = true;
}
}Overall, the article serves as a detailed reference for developers and architects who need to understand Tomcat’s internal structure, configuration, and advanced features such as NIO connectors, pipeline processing, and asynchronous request handling.
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.
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.