Servlet Lifecycle Phases and Request Handling
A Servlet's lifecycle is managed by a web container and consists of four distinct phases:
| Phase | Occurrence | Trigger |
|---|---|---|
| Instantiation | Once | First client request or at startup* |
| Initialization | Once | After instantiation |
| Service | Multiple | For each incoming client request |
| Destruction | Once | When the container shuts down or reloads |
* Instantiation can ocurr at application startup if configured with <load-on-startup>.
During the first request, the container creates a single instance of the Servlet. It then calls the init() method once for setup. For subsequent requests, the container reuses this instance, invoking the service() method in a new thread for each request. The container caches the Servlet instance. When the application stops, the container calls the destroy() method once before garbage collection.
Thread Safety Considerations
Avoid using instance variables in Servlets. Since a single instance serves multiple threads (requests), concurrent modifications can lead to data corruption. If instance variables are necessary, they must be made thread-safe, though this can impact performance. The recommended practice is to minimize or eliminate their use.
Example Servlet Implementation
package com.example.servlets;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class LifecycleDemoServlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("LifecycleDemoServlet initialized");
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("LifecycleDemoServlet handling request");
super.service(request, response); // Delegates to doGet/doPost
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().write("GET request processed");
}
@Override
public void destroy() {
System.out.println("LifecycleDemoServlet destroyed");
}
}
Web Application Deployment Descriptor Configuration
To map the Servlet to a URL and optionally load it on startup:
<servlet>
<servlet-name>lifecycleDemo</servlet-name>
<servlet-class>com.example.servlets.LifecycleDemoServlet</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>lifecycleDemo</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
Request Processing Mechanism
When a client sends a request, the container parses the web.xml file (or uses annotations) to find the mapped Servlet. If not already enstantiated, it creates one, calls init(), and caches it. The container then invokes the service() method in a new thread. The default service() implementation in HttpServlet routes the request to the appropriate method (e.g., doGet() for GET, doPost() for POST) based on the HTTP method. By overriding these methods, developers define custom request handling logic.