Servlet logo
Servlet Tutorial

Overview  
HTTP/CGI  
Servlets  
JSP  
Resources  

Acknowledge Site


 

Introduction | Servlets & HTTP | Life-Cycle | Sessions | Summary | Examples

Life Cycle: Loading | Servicing Requests | Threading | Reloading

Servicing Requests

Once a servlet has been initialised it is ready to handle client requests. Servlet initialisation means that servlet instance is running with the servlet engine and is ready to accept requests. Once loaded, a servlet instance persists across client requests serviced in a multi-threaded manner within the servlet engine. Hence it is imperative that servlets be developed to run within a multi-threaded runtime environment. If your not familiar with writing multi-threaded applications, it is worth taking time out and reading some good books on the subject.

 

Relationship between requests, threads, servlets and the web server

As discussed in section on HTTP/CGI, the main reasons for adopting servlets is to get the flexibility and portability of CGI but with the performance gains of low level server extension APIs such as ISAPI and NSAPI. Another key feature of serlvets is instance persistence. Here, the servlet engine loads a servlet instance that services client requests in a multi-threaded manner. This vastly reduces the amount object creation/destruction and provides a better environment for sharing resources over a prolonged period of time. Take at a look at the following, over-used, example of a servlet counter. It demonstrates nicely the concept of instance persistence:

    package com.ack.servlets;
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.*;
    
    
    public class ServletCounter extends HttpServlet
    {
      private int fInstanceCount;
      private static int fClassCount;
    
      //Process the HTTP Get request
      public void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException
      {
        response.setContentType("text/html");
        PrintWriter out = new PrintWriter (response.getOutputStream());
        out.println("<html>");
        out.println("<head><title>ServletCounter</title></head>");
        out.println("<body>");
    
        synchronized(this)
        {
          out.println("<br>Servlet Instance Count -> " + fInstanceCount++ );
        }
    
        synchronized(getClass())
        {
          out.println("<br>Servlet Total Request Count -> " + fClassCount++ );
        }
    
        out.println("</body></html>");
        out.close();
      }
    }
    

ServletCounter has two counters. fInstanceCount reports the number of times this servlet instance is requested during its lifetime. The total number of times this servlet is requested is given by fClassCount. Running ServletCounter sees the two counters being incremented in unison. This is because the servlet instance has been loaded and is happily servicing client requests. That is, one servlet instance servicing multiple client requests.

When a servlet reload occurs, the servlet instance is destroyed and garbaged collected. The servlet engine will instantiate and initialise a new servlet instance that will have an fInstanceCount of 0. However, fClassCount will maintain its current value because it is the servlet instance and not the servlet class that is reloaded by the servlet engine (we discuss servlet class reloading later).

In Java, synchronization happens at the instance level. However, java.lang.Class is also an object, synchronization actually occurs at both the instance and class level. In this example, we needed both types of synchronization because we had counters at the instance (fInstanceCount) and class (fClassCount) level. In Java it is simple mark thread critical sections in application code. In ServletCounter we used this to lock at the instance level and getClass() to lock at the class level.

One instance per servlet? Not Quite...;-)

Hopefully, at this stage, we have successfully hammered into your head that only one servlet instance is loaded into the servlet engine per servlet class. Well, we sort of lied! Actually, there is one servlet instance per registered servlet name. But why? Well say you have a servlet class that is a front end to a game called Vengance that is played over the Internet. Vengance is a multiplayer game that can be run in either death match mode or team match mode. The Vengance servlet uses initialisation parameters to determine which mode the game should be played in. Although we have one Vengance servlet class, we need two servlet instances. We name one servlet instance DeathMatchVengance and the other TeamMatchVengance. They are two totally different games, two totally different servlets, that are accessed by two totally different sets of players. In short we need two different servlets that are instantiated from the same servlet class. We can achieve this by registering the Vengance servlet class under two different names. Also we configure these two Vengance servlet instances take different initialisation parameters, one for team match mode and the other for death match mode. Hence, the reality is one servlet instance per registered servlet name.

Communicating Errors to the Servlet Engine

What does it mean for a ServletException or UnavailableException to be thrown whilst a servlet is in service? A ServletException signals that an error has occurred during the request and some caretaking needs to be taken by the servlet engine. Note that throwing ServletException could result in a bad response being sent back to the client.

The UnavailableException can have more far reaching consequences on the lifetime of the servlet instance. If the servlet signals that it is permanently unavailable, by throwing:

new throw UnavailableException(theServletInstance, "no more free prizes");

then the servlet engine gracefully removes the servlet instance from service and calls its destroy() method. If the servlet signals temporary unavailability by throwing:

new throw UnavailableException( 25, theServlet, "lost database connection" );

then a well-behaved servlet engine will not route client requests to the servlet but instead return the HTTP response SERVICE_UNAVAILABLE(503) status along with a Retry-After header that tells the client when the service will be back up. However, servlet engines are not being held to this by the specification and they could quite easily treat temporary UnavailableExceptions as permanent. Read your servlet engine document because in this case, throwing temporary UnavailableExceptions will cause that servlet to be permanently removed from service!