|
Introduction
| Servlets
& HTTP | Life-Cycle | Sessions
| Summary
| Examples Life Cycle: Loading | Servicing Requests | Threading | Reloading | ||
Loading & InstantiationBefore a servlet can be loaded, the servlet engine must first locate its class. A servlet class may reside on the local filesystem, a remote filesystem or be some other network resource. The servlet engine must know how to locate the servlet and then use the usual Java class loading facilities to load the servlet class into the JVM. Once loaded, the servlet engine instantiates an instance of that servlet class. InitialisationAn instantiated servlet must be initialised before it is ready to receive client requests. During initialisation the servlet creates and/or gains access to any resources it needs to service client requests. For example, during initialisation a servlet may open a JDBC connection, read configuration data from disk, or write log information to a network resource. The Servlet API provides the init() callback method for a servlet to place all its initialisation logic. Once a servlet has been instantiated the init() is invoked by the servlet engine to initialise the servlet. During initialisation the servlet has access to two key objects: ServletConfig and ServletContext. ServletConfig contains configuration information for the servlet in the form of name/value pairs. How this information is passed to the servlet engine is web server dependent. However, in version 2.2 of the servlet specification, initialisation information is encoded as XML that is parsed and loaded by the servlet engine. From ServletConfig, the servlet developer can get a reference to the ServletContext object. ServletContext gives the serlvet access to information about its runtime environment such as web server logging facilities, version info, URL details, web server attributes, and so on. The following example illustrates a simple servlet initialisation procedure making use of ServletConfig and ServletContext: public class Initialisation extends HttpServlet { // initalise the servlet within init() public void init(ServletConfig config) throws ServletException { super.init(config); ServletContext context = config.getServletContext(); Enumeration initParams = config.getInitParameterNames(); while( initParams.hasMoreElements() ) { String initParam = (String)initParams.nextElement(); context.log(initParam); context.log(config.getInitParameter(initParam)); } log( "Completed Initialisation" ); } //Process the HTTP Get request public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); ... } } The first line of init() should always be super.init(config). This allows GenericServlet to save a reference to ServletConfig and make it available to methods outside of the init() callback. Next, we get hold of the ServletContext and all the initialisation parameter names of the ServletConfig object. The servlet then cycles through all the parameters, outputting their names and values to the web server's log. There are two things to note here. Firstly, GenericServlet exposes a convienence log() method so you don't need to get the ServletContext to log information to the web server. Secondly, web server logs tend buffer information for performance reasons, so during development it may be better to use System.out for viewing debug messages. In the event of errors occurring during the initialisation phase, the servlet instance can throw an UnavailableException or ServletException. These exceptions signal to the servlet engine that initialisation failed and that the servlet cannot service client requests. The servlet engine must acknowledge this, release the servlet instance and put it up for garbage collection. Note that in this case the destroy() method is not called because the servlet instance never completed initialisation. If a servlet has failed to initialise, the servlet engine may want to re-try with a newly instantiated servlet instance. However, if during the first initialisation the servlet it failed to grab a database connection, the servlet developer may want the servlet engine to wait 10 seconds before re-trying. This can be done by throwing an UnavailableException and specifying the minimum number of seconds that the servlet must remain unavailable. For example, the following tells the servlet engine to back of for 15 seconds if it fails to grab a database connection during initialisation: package com.ack.servlets; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; import java.sql.*; public class Initialisation extends HttpServlet { private Connection fConnection; public void init(ServletConfig config) throws ServletException { super.init(config); String jdbcURL = config.getInitParameter("database"); String username = config.getInitParameter("user"); String password = config.getInitParameter("passwd"); UnavailableException uex = null; if( jdbcURL == null || username == null || password == null ) { StringBuffer buf = new StringBuffer("you must specify the "); buf.append (" 'database', 'user', 'passwd' init params to -> "); buf.append( getClass().getName() ); String msg = buf.toString(); log( msg ); throw new ServletException( msg ); } try { // register drivers... fConnection = DriverManager.getConnection(jdbcURL,username,password); // do some work here... } catch( SQLException sqle ) { log( sqle.toString() ); uex = new UnavailableException( 15, this, sqle.toString() ); } finally { // release connection in the event of problems if( uex != null ) try { fConnection.close(); } catch(SQLException e) {} } log( "Completed Servlet Initialisation for: " + getClass().getName() ); } ... } We have loaded a servlet class, instantiated an object instance of that class and initialised it. At this point, the servlet is ready to receive client requests. DestructionFor a successfully initialised servlet, there comes a time when it has to die! The decision of when to destroy a servlet instance again rests on the shoulders of the servlet engine. The servlet specification makes it clear that the lifetime of a servlet can be as short as a few milliseconds to as long as the life time of the servlet engine itself. Servlet developers should not be concerned with these details, but instead focus on what should be done when the time comes. The servlet interface provides the destroy() callback method that is called before the servlet engine can release a servlet. Inside the destroy() method the servlet developer should save any persistent state, release (handles to) shared resources such as database connections and carry out any caretaking tasks. Once the destroy() method has completed the servlet engine releases the servlet and makes it eligible for garbage collection. package com.ack.servlets; import javax.servlet.http.*; import java.sql.*; public class Destruction extends HttpServlet { private Connection fConnection; // other methods public void destroy() { try { if( fConnection != null ) fConnection.close(); } catch( SQLException sqle ) { log( sqle.toString() ); } } } Before this servlet is released, it closes its JDBC database connection. However, the above code is not written in a thread-safe manner because we are not synchronizing access to the servlet's instance variable fConnection. The reason for this is that destroy() is executed within a single thread. In fact, before the servlet engine can call the destroy() method, it must allow all threads currently executing in its service() method to complete. Note that the init() method should, in theory, also be thread-safe. But it is better to be safe than sorry and implement both init() and destory() so that they can run within multi-threaded environments. In the next section, we describe how servlets are multi-threaded in their handline of HTTP requests. But what happens in the event of a server crash? Will a servlet's destroy() method be called, its state information saved and resources released? Well one thing is for sure, if a servlet isn't in it's destroy() method when the server goes down, it will not be called by the servlet engine. In a server crash/reboot scenario, all resources will be released but your application state information will be lost. It is an application-dependent decision as to when and how often a servlet's state information needs to persisted. For example, a chat server may want to save state every time someone posts a message to the server, where a shopping cart implementation need only do it when items are added/removed from the basket. SummarySo we know how and when a servlet is loaded, instantiated, initialised and destroyed. In the next section we learn how servlets handle client requests when in the ready state. | |||
(c) Zameer's Online Education 2006 |