The Servlet Lifecycle
In the last lesson we took a much closer look at servlets by looking at the anatomy of the
javax.servlet.Servlet interface and the
abstract classes. We touched on the fact that three of the methods of the
destroy() were lifecycle methods.
In this lesson we look at these methods in much greater detail as we look at the life of a servlet.
The Life Of A Servlet
We can think of an object's lifecycle as the various stages that said object goes through during its existence. Because a servlet has to run within the boundaries of whatever web container we are using, there are additional factors involved with the lifecycle of a servlet object.
The following slideshow shows the various stages in the servlet lifecycle. Press the button below to step through the slideshow:
Our client has clicked on a link that points to a resource that is a servlet rather than a static HTML page, so the web server directs the HTTP request to our web container.
This servlet has not been called by the container before so will have to be loaded by the application's class loader.
Just like any other object our servlet has to be instantiated so it can be called by the container. The container calls the default no-args constructor which is best left to the compiler to
Now we have a servlet object the first of the three lifecycle methods, the
init() method is called for the first and only time, and is where the initialisation of the servlet takes place.
The second of the three lifecycle methods, the
service() method is called on our initialized servlet. This invokes one of the
doXXX() methods, dependant upon the
incoming HTTP method passed with the client request and thus services the request from the client. A response is created and passed back to the client.
The servlet sits there in its initialized state happily servicing requests from clients and sending back responses.
The third and final lifecycle method, the
destroy() method is called on our servlet. This can happen for a number of reasons including server shutdown and an application being undeployed.
We will go into the different stages of the servlet lifecycle shown in the slideshow in much more detail and answer some other questions raised by it as we go through the rest of the lesson.
A container can contain many web applications and each of these has a class loader that is used to search for and load classes from the
/WEB-INF/classes/ directory and JAR files from
/WEB-INF/lib/ directory. Having separate class loaders for each application allows servlets in different applications to have the same name but also means that servlets within one application can
only communicate with servlets in another application via the container interface.
Because the container finds a class it doesn't necessarily load it; the default behaviour is to lazily initialise servlets on first use or when the container deems it necessary. We can also set servlets to load on deployment or server restart, via the DD. This is achieved using the <load-on-startup> sub-level element of the top-level<servlet> element, an example of which is shown below.
<servlet> <servlet-name>myServlet</servlet-name> <servlet-class>test.Servlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>
Don't worry too much about the DD elements shown above for now, suffice to say that any positive integer value placed in the <load-on-startup> sub-level element will ensure that a servlet is loaded on deployment or server restart. If you have several servlets in your web application you can also control the order in which servlets are loaded via the <load-on-startup> sub-level element. The servlets with the highest <load-on-startup> integer values get loaded first down to the lowest with a positive value.
Just like any other object our servlet has to be instantiated so it can be called by the container. The thing to remember here is that although we will, in the vast majority of cases, extend the
class when creating our own servlets the container isn't aware of any particular protocol being used and so must instantiate each servlet in a generic manner. This is achieved using the default no-args constructor
which is best left to the compiler to generate. If you absolutely must have a custom constructor for your servlet then you also need to explicitly code a no-args constructor so the container can instantiate your
You cannot do any initialisation at this stage as our servlet doesn't exist in what we can think of as a servlet state until the no-args constructor has completed and the container makes it into a servlet object. Any attempts to initialise the servlet using other parts of the application will fail and is the reason why we have separate instantiation and intialisation steps.
We now have a fully fledged servlet object waiting to be initialized to its default state. Here is a good time to talk about what value we get from a normal object being transformed into a servlet object. Well
apart from the benefits we get from the container every servlet also gets access to two other objects, these being
Each servlet gets one
ServletConfig object and this is where we can put configuration information for deployment rather than in a constructor. We configure initialisation parameters for the
object via the DD. This is achieved using the <init-param> sub-level element of the top-level
<servlet> element, an example of which is shown below.
<servlet> <servlet-name>myServlet</servlet-name> <servlet-class>test.Servlet</servlet-class> <init-param> <param-name>email</param-name> <param-value>mailto:[email protected]</param-value> </init-param> </servlet>
Once again don't worry too much about the DD elements shown above for now but a point of note is that we can have multiple entries of the <init-param> sub-element.
ServletConfig object also allows us to access the other object we get with a servlet, the
Each web application gets one
ServletContext object and we can get information about the versions of the container and API being used from this object. We can also configure application wide
parameters for the
ServletContext object via the DD. This is achieved using the <param-name> and <param-value> sub-level elements of the
<context-param> top-level element, an example of which is shown below.
<context-param> <param-name>disclaimer</param-name> <param-value>legaldoc.txt</param-value> </context-param>
We will go into much more detail about the
ServletContext objects in the ServletConfig & ServletContext lesson, but a point of note is
that we can have multiple entries of the <context-param> element within the DD.
init() Lifecycle Method
init() lifecycle method is the first of the three lifecycle methods associated with a servlet and is run only once during the life of a servlet. You can put initialisation code required by your
servlet that cannot be placed declaratively within the DD in this method, such as Java code for referencing and database connections.
If you are implementing the
Servlet interface directly then you will have to override the
init(ServletConfig config) method. If you are extending the
GenericServlet class and need to
init(), use the convenience no-args
init() method for this purpose, rather than the
init(ServletConfig config) method. The reasoning behind this is that the
init(ServletConfig config) method is always run first and stores a local copy of the
ServletConfig object which can be retrieved later using the
init(ServletConfig config) method then delegates any further processing to the no-args
init() method which is why you will want to override this method.
init() methods can throw a
ServletException or a subclass thereof and if this happens the container bypasses the other lifecycle methods and makes the servlet available for garbage collection.
So our one time initialisation has completed and our servlet is now ready to process requests. When a request from a client comes in the
service(ServletRequest req, ServletResponse resp) method is
invoked. If you are extending the
Servlet class you will need to override this method in your implementation. If you are extending the
GenericServlet class then a concrete implementation
is available for use and you will have to provide the protocol methods for whichever protocol you are using. For the majority of incoming requests what we are really interested in is the HTTP protocol and so our
servlets will be extending the
service() Lifecycle Method
The service() lifecycle method is the second of the three lifecycle methods associated with a servlet and is run every time a client requests a service. When we extend the
HttpServlet class with our own
servlets we need to override one of the
doXXX() methods, dependant upon the incoming HTTP method passed with the client request.
What happens is the generic
service(ServletRequest req, ServletResponse resp) method dispatches the incoming request to the
service(HttpServletRequest req, HttpServletResponse resp) HTTP
protocol specific method. This method will then delegate servicing to one of the HTTP
doXXX() methods, dependant upon the incoming HTTP method passed with the client request. All our servlet needs to do
is override the
doXXX() method with our business code to service the request from the client.
The following table should help clarify this and there are links back to each HTTP method if you need a refresher on what each does.
|HTTP Method||doXXX() Method||Description|
|DELETE||Called by server, via |
|GET||Called by server, via |
|HEAD||Receives a HTTP |
|OPTIONS||Called by server, via |
|POST||Called by server, via |
|PUT||Called by server, via |
|TRACE||Called by server, via |
You should always override at least one of the
doGet() methods as failure to do so will result in a
HTTP status code being returned from HTTP/1.0 and a
405('Method Not Allowed') HTTP status code being returned from HTTP/1.1.
service() methods can throw a
ServletException or a subclass thereof and if this happens and the exception is permanent the container returns a
404('Not Found') HTTP status
code and removes the servlet from service. If the exception is temporary the container returns a
503('Service Unavailable') HTTP status code and makes the servlet temporarily unavailable. After a
period of time the container will put the servlet back into service, making it available to service more requests. The
service() methods can also throw an
IOException as we are accessing
writers which can cause exceptions.
The final phase of a servlets lifecycle is its destruction and can happen for a number of reasons including server shutdown and an application being undeployed. When such an event happens the container will call
destroy() method which gives us an opportunity to free resources and tidy up before the servlet is garbage collected.
destroy() Lifecycle Method
destroy() lifecycle method is the last of the three lifecycle methods associated with a servlet and is run only once during the life of a servlet. This method is invoked by the container
when a servlet is going to be destroyed and gives us a chance to clean up and housekeep before the servlet is garbage collected. If you are extending the
Servlet class you will need to override this
method in your implementation. If you are extending the
GenericServlet class then a concrete implementation is available for use and if no housekeeping is required is prefectly adequate. Dependant upon
resources being used you may want to override this method in your own servlet code.
Lesson 5 Complete
In this lesson we looked at the servlet lifecycle, from the loading and instantiation of a servlet to its eventual destruction.
In the next lesson we write our first servlet and look at the processes involved.