MTI TEK
  • Home
  • About
  • LLMs
  • Docker
  • Kubernetes
  • Java
  • All Resources
Java Servlet | Servlet
  1. What is a Servlet?
  2. Understanding the Servlet Lifecycle
    1. Phase 1: Class Loading
    2. Phase 2: Instance Creation
    3. Phase 3: Initialization - init() Method
    4. Phase 4: Request Processing - service() Method
    5. Phase 5: Cleanup - destroy() Method
  3. Servlet Configuration and Initialization Parameters

  1. What is a Servlet?
    A servlet is a server-side Java class that conforms to the Java Enterprise Edition (JEE) specification for handling web requests and responses. Servlets are managed by a servlet container (such as Apache Tomcat or Jetty) and serve as the foundation for building dynamic web applications.

    Key characteristics of servlets:
    • They extend the HttpServlet class or implement the Servlet interface.
    • They run on the server side and generate dynamic content.
    • They follow a specific lifecycle managed by the servlet container.
    • They can handle multiple concurrent requests efficiently through multithreading.

    The servlet container is responsible for loading, initializing, and managing servlets throughout their lifecycle. It dynamically invokes specific methods defined by the servlet specification to handle various events such as HTTP requests, initialization, and cleanup operations.
  2. Understanding the Servlet Lifecycle
    The servlet lifecycle consists of five distinct phases that are managed entirely by the servlet container. Each phase serves a specific purpose and occurs at predetermined times during the servlet's existence.
    1. Phase 1: Class Loading
      The servlet container loads the servlet class into memory using the Java ClassLoader mechanism. This is typically the first step in the servlet lifecycle, though the exact timing can vary based on configuration and container implementation.

      Class loading can occur:
      • At servlet container startup (eager loading).
      • When the web application is deployed.
      • Upon receiving the first request to the servlet (lazy loading - default behavior).
      • At any point between container startup and the first request, based on container optimization strategies.

      The load-on-startup element in web.xml can control this timing. A positive integer value forces eager loading, with lower numbers loading first.

      Once the class is successfully loaded into the JVM:
      • All static fields are initialized with their default or assigned values (e.g., static String myVar1 = "default";).
      • All static initialization blocks are executed in the order they appear (e.g., static { /* initialization code */ }).
      • The class becomes available for instantiation.
    2. Phase 2: Instance Creation
      Immediately after class loading, or when the servlet container determines that a new instance is needed, the container creates an instance of the servlet class using the default constructor. Most servlet containers maintain a single instance per servlet class (singleton pattern), but this can vary based on implementation.

      During instantiation, the following occurs in sequence:
      • Memory is allocated for the instance.
      • All instance fields are initialized with their default or assigned values.
      • All instance initialization blocks are executed in declaration order.
      • The no-argument constructor is invoked (if explicitly defined).

      Important Note: The servlet specification requires a public no-argument constructor. If not explicitly provided, the Java compiler automatically generates one, unless other constructors with parameters are declared. If parameterized constructors exist without a no-argument constructor, instantiation will fail.

      Since servlets typically handle multiple concurrent requests using the same instance, it's crucial to avoid instance variables for request-specific data to prevent thread safety issues.
    3. Phase 3: Initialization - init() Method
      The initialization phase occurs immediately after successful instantiation and is executed exactly once per servlet instance throughout its entire lifecycle. The servlet container calls the init() method to allow the servlet to perform one-time setup operations.

      There are two overloaded versions of the init method:
      • init(ServletConfig config) - receives configuration information.
      • init() - convenience method for custom initialization logic.

      Common initialization tasks include:
      • Loading configuration properties.
      • Establishing database connections or connection pools.
      • Initializing shared resources.
      • Setting up logging mechanisms.
      • Reading initialization parameters from web.xml.

      The servlet container guarantees that the init() method completes successfully before any requests are processed. If initialization fails, the servlet becomes unavailable for request processing.

      Initialization can fail in two scenarios:
      • Timeout: The execution time exceeds the container's configured maximum initialization time limit.

      • Exception: The method throws a ServletException or UnavailableException.
        The UnavailableException allows specifying either permanent unavailability or a temporary duration after which the servlet may be retried.
    4. Phase 4: Request Processing - service() Method
      The service phase represents the core functionality of a servlet, where actual request processing occurs. This method is invoked by the servlet container for each incoming HTTP request, potentially handling multiple concurrent requests using separate threads but typically sharing the same servlet instance.

      The service() method has two main variants:
      • service(ServletRequest req, ServletResponse res) - generic servlet interface.
      • service(HttpServletRequest req, HttpServletResponse res) - HTTP-specific implementation.

      The HttpServlet class provides a sophisticated implementation that automatically dispatches requests to appropriate handler methods based on the HTTP method (GET, POST, PUT, DELETE, etc.). This dispatch mechanism eliminates the need for manual method checking in most cases.

      Request processing flow:
      1. Container receives HTTP request
      2. Container determines target servlet
      3. Container calls service() method
      4. Method examines HTTP method and delegates to appropriate doXXX() method
      5. Handler method processes request and generates response
      6. Response is sent back to client

      Here is a simplified view of the service() method from the HttpServlet class:
      package jakarta.servlet.http;
      
      public abstract class HttpServlet extends GenericServlet implements Serializable {
          protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              String method = req.getMethod();
      
              if(method.equals("GET")) {
                  doGet(req, resp);
              } else if(method.equals("POST")) {
                  doPost(req, resp);
              } else if(method.equals("HEAD")) {
                  doHead(req, resp);
              } else if(method.equals("OPTIONS")) {
                  doOptions(req, resp);
              } else if(method.equals("TRACE")) {
                  doTrace(req, resp);
              } else if(method.equals("PUT")) {
                  doPut(req, resp);
              } else if(method.equals("DELETE")) {
                  doDelete(req, resp);
              } else {
                  sendMethodNotAllowed(req, resp);
              }
          }
      }
      Thread safety considerations:
      • Multiple threads may execute the service method simultaneously.
      • Instance variables should be avoided for request-specific data.
      • Synchronization should be used cautiously to avoid performance bottlenecks.
      • Local variables and method parameters are thread-safe.
    5. Phase 5: Cleanup - destroy() Method
      The destruction phase marks the end of a servlet's lifecycle and provides an opportunity to perform cleanup operations before the instance is removed from memory. The servlet container calls the destroy() method when it decides to terminate the servlet instance.

      Common scenarios triggering servlet destruction:
      • Servlet container shutdown.
      • Web application undeployment or redeployment.
      • Memory optimization (container decides to free unused instances).
      • Administrative actions (manual servlet stopping).
      • Container maintenance operations.

      Before calling destroy(), the container ensures:
      • All threads currently executing the service() method have completed.
      • No new requests are routed to the servlet instance.
      • A reasonable timeout period has passed for request completion.

      If the timeout is exceeded, the container may forcibly terminate request processing threads.

      Typical cleanup operations include:
      • Closing database connections or connection pools.
      • Releasing file handles and I/O resources.
      • Shutting down background threads.
      • Clearing caches or temporary data.
      • Logging shutdown information.

      Important: The destroy() method will never be called if the init() method failed during initialization. This prevents cleanup operations on improperly initialized servlets.
    Lifecycle Example:
    package com.mtitek.servlets.test1;
    
    import java.io.IOException;
    
    import jakarta.servlet.ServletConfig;
    import jakarta.servlet.ServletException;
    import jakarta.servlet.ServletRequest;
    import jakarta.servlet.ServletResponse;
    import jakarta.servlet.http.HttpServlet;
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    
    @SuppressWarnings("serial")
    public class MyServlet2 extends HttpServlet {
        @Override
        public void init(ServletConfig config) throws ServletException {
            System.out.println("MyServlet2 : init(ServletConfig) : Start");
            super.init(config);
            System.out.println("MyServlet2 : init(ServletConfig) : End");
        }
    
        @Override
        public void init() throws ServletException {
            System.out.println("MyServlet2 : init() : Start");
            super.init();
            System.out.println("MyServlet2 : init() : End");
        }
    
        @Override
        public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
            System.out.println("MyServlet2 : service(ServletRequest, ServletResponse) : Start");
            super.service(request, response);
            System.out.println("MyServlet2 : service(ServletRequest, ServletResponse) : End");
        }
    
        @Override
        public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("MyServlet2 : service(HttpServletRequest, HttpServletResponse)");
        }
    
        @Override
        public void destroy() {
            System.out.println("MyServlet2 : destroy() : Start");
            super.destroy();
            System.out.println("MyServlet2 : destroy() : End");
        }
    }
    Console output when the servlet is accessed:
    MyServlet2 : init(ServletConfig) : Start
        MyServlet2 : init() : Start
        MyServlet2 : init() : End
    MyServlet2 : init(ServletConfig) : End
    
    MyServlet2 : service(ServletRequest, ServletResponse) : Start
        MyServlet2 : service(HttpServletRequest, HttpServletResponse)
    MyServlet2 : service(ServletRequest, ServletResponse) : End
    The output demonstrates the method execution order and the inheritance chain behavior where superclass methods are invoked through super calls.
  3. Servlet Configuration and Initialization Parameters
    Servlet initialization parameters provide a mechanism for configuring servlet behavior without hardcoding values in the source code. These parameters are defined in the web application deployment descriptor (web.xml) and are accessible to the servlet during and after initialization.

    Initialization parameters are defined within the <servlet> element using <init-param> elements, each containing a <param-name> and <param-value> pair. These parameters are read-only and remain constant throughout the servlet's lifecycle.

    Common use cases for initialization parameters:
    • Database connection strings and credentials.
    • File paths and directory locations.
    • Configuration flags and operational modes.
    • Third-party service endpoints and API keys.
    • Performance tuning parameters.

    The servlet API provides two methods for accessing initialization parameters:
    • String getInitParameter(String name)
      Retrieves the value associated with the specified parameter name. Returns null if the parameter does not exist. This method is case-sensitive and returns the exact string value as defined in web.xml.

    • Enumeration<String> getInitParameterNames()
      Returns an enumeration containing all initialization parameter names defined for the servlet. If no parameters are configured, an empty enumeration is returned. This method is useful for dynamically discovering available parameters.

    Configuration and Usage Example:
    • web.xml configuration:
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
              version="3.0">
      
          <servlet>
              <servlet-name>MyServlet1N1</servlet-name>
              <servlet-class>com.mtitek.servlets.test1.MyServlet1</servlet-class>
              <init-param>
                  <param-name>myservlet1n1_param_name_1</param-name>
                  <param-value>myservlet1n1_param_value_1</param-value>
              </init-param>
              <init-param>
                  <param-name>myservlet1n1_param_name_2</param-name>
                  <param-value>myservlet1n1_param_value_2</param-value>
              </init-param>
              <load-on-startup>1</load-on-startup>
          </servlet>
      
          <servlet-mapping>
              <servlet-name>MyServlet1N1</servlet-name>
              <url-pattern>/MyServlet1UP1</url-pattern>
          </servlet-mapping>
      </web-app>

    • MyServlet1.java implementation:
      package com.mtitek.servlets.test1;
      
      import java.io.IOException;
      import java.io.PrintWriter;
      import java.util.Enumeration;
      
      import jakarta.servlet.ServletException;
      import jakarta.servlet.http.HttpServlet;
      import jakarta.servlet.http.HttpServletRequest;
      import jakarta.servlet.http.HttpServletResponse;
      
      @SuppressWarnings("serial")
      public class MyServlet1 extends HttpServlet {
          @Override
          public void service( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
              response.setContentType("text/html");
              PrintWriter out = response.getWriter();
              
              out.println( "<html><title>servlet - Hello, world!</title><body>" );
              out.println( "<h1>servlet - Hello, world!</h1><hr /><br />" );
      
              out.println( "<b>Servlet Name:</b> " + getServletName() + "<br /><br />");
              
              out.println( "<b>Initialization Parameters:</b><br />");
              Enumeration<String> initParameterNames = getInitParameterNames();
              
              if (!initParameterNames.hasMoreElements()) {
                  out.println("No initialization parameters found.<br />");
              } else {
                  while (initParameterNames.hasMoreElements()) {
                      String initParameterName = initParameterNames.nextElement();
                      String initParameterValue = getInitParameter(initParameterName);
                      out.println("<b>" + initParameterName + ":</b> " + initParameterValue + "<br />");
                  }
              }
      
              out.println( "</body></html>" );
              out.close();
          }
      }
© 2025 mtitek