The primary reason why servlets and JavaServer Pages (JSP) outperform traditional CGI is the servlet life cycle. Servlets have a three-phase life cycle, namely initialization, service, and destruction. initialization and destruction are called only once in the entire lifecycle while service is can call multiple times in lifecycle.
Initialization is the first phase of the servlet lifecycle. It represents the creation and initialization of the resources the servlet may need in response to service requests. All servlets must implement the javax.servlet.Servlet interface, which defines the init() method that corresponds to the initialization phase of a servlet life cycle. As soon as a servlet is loaded in a container, the init() method is invoked before servicing any requests.
The second phase of a servlet life cycle is the service phase. This phase of the servlet life cycle represents all the interactions carried out along with the requests that are handled by the servlet until it is destroyed. The service phase of the servlet life cycle corresponds to the service() method of the Servlet interface. The service() method of a servlet is invoked once for every request.
The service() method takes two object parameters, javax.servlet.ServletRequest and javax.servlet.ServletResponse. These two objects represent a request for the dynamic resource from a client and a response sent by a servlet to the client, respectively. A servlet is usually multithreaded. This implies that a single instance of a servlet is loaded by a servlet container at a given instance, by default. The initialization of the servlet is done only once and after that, each request is handled concurrently by threads executing the service() method of the servlet.
The third and final phase of the servlet life cycle is the destruction. This phase represents the termination of the servlet execution and its removal from the container. The destruction phase corresponds to the destroy() method of the Servlet interface. The container calls the destroy() method when a servlet is to be removed from the container.
The invocation of the destroy() method enables the servlet to terminate gracefully and clean up any resources held or created by it during execution. To efficiently manage application resources, a servlet should properly use all the three phases of its life cycle. A servlet loads all the required resources during the initialization phase, which may be needed to service client requests. The resources are used during the service phase and then can be given up in the destruction phase.
We have discussed the three events or phases that form the life cycle of a servlet. However, there are many more methods that need to be considered by a Web developer. HTTP is primarily used to access content on the Internet. Through a basic servlet does not know anything about HTTP, a special implementation of the servlet, namely javax.servlet.http.HttpServlet has been specifically designed for this purpose.
When the Servlet container creates a servlet for the first time, the container invokes the init() method of the servlet. After this, each user request results in the creation of a thread, which calls the service() method of the respective instance. Though the servlet in question can implement a special interface, (SingleThreadModel), which stipulates that not only a single thread is permitted to run at a time, but also multiple concurrent requests can be made. The service calls the doGet(), do Post(), or any other doXXX() method. However, the calling of the doXXX() method depends on the type of HTTP request received. Finally, when the server decides to unload a servlet, it first calls the servlet’s destroy() method.
Let’s now discuss the various methods used in the life cycle of the Servlet.
The init() Method
As mentioned earlier, the init() method is called when a servlet is created for the first time. It will not be called again for other user requests. Therefore, the init() method is used only for one-time initializations. A servlet is normally created when a user invokes a URL corresponding to the servlet, for the first time; however, the servlet is loaded on the server when a Servlet container maps the user request to the servlet. The following code snippet shows the init() method definition:
// Initialization code…
Reading server-specific initialization parameters is one of the most common tasks that the init() method performs. When you need to read the initialization parameters, you have to first obtain a ServletConfig object by using the getServletConfig() method, and then call the getInitParameter() method on the result. The following code snippet shows how to obtain a ServletConfig object:
ServletConfig config = getServletConfig():
String paraml = config.getInitParameter(“parameter1”);
In the preceding code snippet, notice that the init() method uses the getServletConfig() method to obtain a reference to the ServletConfig object. The object has a getInitParameter() method, which can be used to look up the initialization parameters associated with the servlet. Similar to the getParameter() method used in the init() method of applets, both the input (i.e., the name of the parameter) and the output (i.e., the parameter value) are nothing but Strings.
You can read the initialization parameters by calling the getInitParameter() method of the ServletConfig object. However, setting up these initialization parameters is the job of the web.xml file, which is called Deployment Descriptor.
The service() Method
Each time a server receives a request for a servlet, the server spawns a new thread and calls for the service() method. It is possible that the server spawns a new thread by reusing an idle thread from a thread pool. The service() method verifies the HTTP request type (GET, POST, PUT, DELETE) and accordingly calls the doGet(), doPost(), doPut(), doDelete() methods. A normal request for a URL or a request from an HTML form that has no METHOD specified results in a GET request. Apart from the GET request, an HTML form can also specify POST as the request method type. The following code snippet explains the implementation of the POST method:
<form name=”greetForm” method=”post”>
Now, if you’ve got a servlet that must handle both GET and POST and obtain requests identically, you’ll be tempted to override the service () method directly instead of implementing both the doGet() and doPost () methods. However, remember, this is not a good idea. Instead, just you can use the doPost() method to call the doGet() method (or vice versa), as shown in the following code snippet:
// Servlet code
public void doPost (HttpservletRequest request, HttpServletResponse response) throws ServletException, IOException
In the preceding code snippet, the @Override annotation is used. Though this approach takes a couple of extra lines of code, it has several advantages over the approach of directly overriding of the service() method. One advantage is that you can add support for other HTTP request methods later by adding the do Put(), doTrace() methods in a subclass. Another advantage of using this approach is that you can add support to retrieve the date on which modifications on data have been made by adding the getLastModified() method. However, overriding the service () method eliminates this option because the getLastModified() method invoked by the default service() method. Finally, as an added advantage, you can get automatic support for the HEAD, OPTIONS, and TRACE requests.
If a servlet needs to handle both GET and POST identically, the doPost() method should call the doGet() method or vice versa. Remember, you should not override the service method directly
During the entire request and response process, most of the time, you only care about the GET POST requests. Therefore, you override either the doGet() method or the doPost() method or both. However, if required, you can also override the following methods depending upon the request types:
- The doDelete() method for DELETE requests
- The doPut() method for PUT requests
- The doOptions() method for OPTIONS requests
- The doTrace() method for TRACE requests
Remember, however, that you have automatic support for OPTIONS and TRACE.
The doHead() method is not provided in versions 2.1 and 2.2 of the Servlet API, because in those versions the system answers HEAD requests automatically by using the status line and header settings of the doGet() method. However, the doHead() method is included in version 2.3 to enable the generation of responses to HEAD requests.
The destroy() Method
The destroy() method runs just one occasion during the lifetime of a servlet, and signals the last of the servlet instance. A Servlet container holds a servlet instance till the servlet is active or its destroy() method is activated. The following code snippet shows the method signature of the destroy() method:
As soon because the destroy() method is activated, the Servlet container releases the servlet instance.
It is not recommended to implement the finalize() method in the servlet object instead, provide the code for the finalization tasks of an application in the destroy() method.