
What is the Servlet API?
Now that we've looked at the environment within which the Servlet API executes, the remainder of this chapter is pointed squarely at the Servlet API. This API is one of the oldest within the Java Enterprise Edition family—its first incarnation dates back to 1997.
In this section, we'll take a quick walk through JSR 154 for the Servlet 2.5 API.
Note
The information in this section is applicable to all Java EE compliant servlet containers, including those contained in IBM WebSphere and BEA WebLogic, as well as to Apache Tomcat.
The word 'servlet' conjures up an image of a baby server, and that is exactly what it is. It is a play on the word 'applet', which represents a baby application.
A servlet is a web component, a pluggable piece of functionality that is written in Java and deployed to a web container to extend the container's functionality in a very custom way.
For all intents and purposes, a servlet functions in a very similar manner to its bigger sibling—the web server/container. It waits around for incoming requests, jumps up to process them, returns a response (most usually as HTML), and then returns to waiting for the next request.
What makes servlets attractive is that the average developer can quickly extend server functionality without being aware of low level network programming details like sockets and protocols and can instead focus on higher level abstractions such as requests, responses, and sessions.
Servlet container
As we have discussed earlier, the Java EE architecture is based on a containment hierarchy, where components that contain your application logic are deployed into containers that manage the life cycle of their contained components and provide those components with various enterprise services.
In the Servlet API, the central role is played by the servlet container into which web components, such as servlets, JSP pages, filters, and event listeners are deployed. The servlet container is responsible for managing their life cycles, and also provides access to Service APIs like JNDI and JAXP.
For example, in the case of a servlet component, the container's life cycle management process includes instantiating an instance of that servlet on first access, calling its init()
method to allow it to initialize itself, calling its service()
method once for each request that comes in for that servlet, and then when the servlet is ready to be taken out of service, calling its destroy()
method to release its resources.
The following diagram depicts the typical process flow for a request for a given servlet:

From the previous diagram, the process flow may be explained as follows:
- A client browser requests a resource on the web server.
- The web server checks the request. If it is for a static resource, the web server locates the static resource and transmits it to the client. Skip to step 6.
Note
The Tomcat container, when deployed in standalone mode, can play the roles of both the web server and a servlet container and can serve up both static and dynamic resources.
- If it is for a dynamic resource that is being served up by a servlet container, the web server delegates to the servlet container instead, which must locate the servlet that will process this request. It uses the request URI as well as the mappings declared in the deployment descriptor to locate the appropriate servlet. If the servlet is already loaded and initialized, then skip to step 4.
Otherwise, the appropriate servlet class is located, loaded, and instantiated. The servlet's
init()
method is then called, to give it a chance to initialize itself. - It then invokes the
service()
method of the servlet to generate the appropriate response. - The response is generated.
- The web server returns the completed response to the client browser.
- The client browser renders the rendered response.
Core servlet classes
This diagram represents the classes that make up the core Servlet API.

This image provides a summary of key aspects of the Servlet API. As shown, the Servlet API is designed to be protocol agnostic. This design goal can be seen by the fact that GenericServlet
deals with a generic ServletRequest
and ServletResponse
, whereas HttpServlet
uses the HTTP protocol specific HttpServletRequest
and HttpServletResponse
.
However, the only protocol that is currently used with servlets is HTTP. As a result, you will normally always work with a javax.servlet.http.HttpServlet
.
The javax.servlet.Servlet
interface defines key lifecycle methods that are invoked at appropriate points in a servlet's life by the container.
After a servlet is first loaded and instantiated, its init(ServletConfig)
method is called, so as to provide it with its initialization parameters, as well as to allow it to access its runtime context through this ServletConfig
parameter. Only after the init()
method completes, will the servlet be asked to service any incoming requests. A servlet will typically use this opportunity to initialize any resources that it needs for its functioning.
The service()
method is called once per incoming request for this servlet.
The destroy()
method is called by the container just before the servlet is taken out of service and gives the servlet a chance to release any resources that it has acquired.
The GenericServlet
abstract class defines an init()
method that takes no parameters. This is a convenience method that is called by the default init(ServletConfig)
method to execute any application-specific servlet initialization. The default implementation does nothing, and is provided for subclasses to override.
Though the service()
method in this class is marked abstract, you will rarely, if ever, override the service()
method. Instead, the service()
method is implemented by javax.servlet.http.HttpServlet
which inspects the incoming HTTP method and invokes the appropriate method for that request type. There are seven request methods defined by HTTP/1.1, and the HttpServlet
class provides default implementations for each of these methods that you may choose to override. Most application developers write servlets that override only the doGet()
and doPost()
methods.
The HttpServlet
also has a getLastModified()
method that supports caching of resources. When a client browser is attempting to reload a resource, it can send in an If-Modified-Since
request header to have the server check to see if a newer version of the resource is available.
The getLastModified()
method lets the server query the servlet for the time that this servlet last modified its output. This method returns a long
return value that indicates the time at which this resource was last modified.
The server can compare the returned time to the If-Modified-Since
request header, and if the content has not changed, then it simply returns a response status to the client that indicates that the resource has not been changed from its previous state.
If the server indicates that a newer version is not available, the browser can simply use the resource in its cache.
An instance of the javax.servlet.ServletConfig
interface is little more than a holder for the servlet context, as well as per-servlet initialization parameters that are specified by the deployer in the deployment descriptor as String
name-value pairs.
A javax.servlet.ServletContext
instance represents the web application to which this servlet belongs. A servlet context represents the collection of web components (servlets, filters, listeners, and JSP files), utility classes, library JARs, static content (HTML, CSS, JavaScript, and so on), and other resources that are made available to clients under a specific context path within the servlet container. There is one context per web application that is deployed into the container.
The ServletContext
provides access to attributes that are placed into the context scope (also known as, application scope). The ServletContext
object is accessed through the ServletConfig
object, which the container provides to the servlet when the servlet is initialized.
Note
A web application deployed to a container can usually be represented by a single ServletContext
instance within a Java Virtual Machine. This ensures that attributes in the ServletContext
are truly global variables for that JVM.
However, it is to be noted that in a clustered environment, there will be many cooperating Java Virtual Machines in existence.
The topic of deploying web application contexts in a clustered environment is out of scope for this book.
Servlets are inherently multithreaded. In other words, the servlet container will create only one instance per servlet declaration within the deployment descriptor. (Note that this is per declaration and not per servlet class.)
As a result, at any given time, multiple processor threads within the container may be executing within a servlet instance's service()
method. It is the servlet developer's responsibility to ensure that this invocation is thread-safe.
Note
Multithreading is the mechanism by which multiple threads of execution can be started within a single process.
Each thread of execution has its own copy of local variables but will see common state when executed within the context of an object or when considering global application state. This is where a lot of the problem begins.
New programmers often make the mistake of assuming that their code will never be executed in a multithreaded context, and when it eventually is (as in any Java EE environment), strange and hard-to-reproduce bugs invariably result.
A common solution is to make code that will be traversed by multiple threads stateless. In other words, all the information required by that code is passed in as arguments, resulting in reliance on local variables alone.
However, this is not always possible. In such cases, we need to rely on the synchronization facilities that are provided by the Java programming language. These facilities allow us to mark critical sections of code to which the JVM will serialize any access by multiple concurrent threads.
This topic is fairly involved, and the interested reader is referred to any number of texts on the Java programming language for additional details.
When we consider this possibility, the simple diagram that we saw earlier tends to get just a tiny bit more complicated. In the following diagram, the container now has three processor threads, and each thread is currently in the process of handling a request of a different client.

This container has two servlet instances, servlet1
of the class Servlet1
and servlet2
of the class Servlet2
.
When Client1
makes a request (1a), the container retrieves a free thread, Thread1
, from the thread pool (1b) and asks it to process the request. Thread1
begins by building the request and response objects (1c), locates the appropriate servlet that should process this request (1d), and invokes the servlet instance's service()
method (1e). The response generated by the servlet is then returned to the client (1f), and is rendered by Client1
(1g).
The flows 2a through 2g and 3a through 3g follow a similar pattern.
Let us take a snapshot of this system while all three threads are executing within the appropriate service()
methods. At this particular instant in time, both processor thread Thread1
and processor thread Thread2
are in the process of executing servlet1.service()
, whereas processor thread Thread3
is in the process of executing servlet2.service()
.
Any instance variables of the servlet1
instance are now being accessed concurrently by both Thread1
and Thread2
. Therefore, they must be protected against corruption. Likewise, any variables in context or session scope (which we'll see later) may be accessed simultaneously by all three threads, and so must also be protected against concurrent access.
An incoming request is represented by an implementation of the javax.servlet.http.HttpServletRequest
interface. This interface extends the protocol-agnostic ServletRequest
with HTTP-specific characteristics.

This image depicts key aspects of the request interfaces within the Servlet API.
The lifetime of a request object is intended to be the duration of a request. It is constructed by the container from the incoming HTTP request.
It exposes operations that allow a servlet to manipulate the incoming request and to extract various pieces of information from it.
Request parameters and request attributes are both name-value pairs, but the similarity ends there.
A request parameter represents a form parameter that comes in on the incoming request, either as part of the request's payload, or in the URL query string. The value of each named parameter is always a standard Java String
.
On the other hand, a request attribute is a named object that is set on the HttpServletRequest
by a web component, such as a filter or a servlet. The value of an attribute can be any Java object. A request attribute is meant to be used only during the current request processing cycle and is a convenient way to cache objects while processing a request or to transfer arbitrary objects to another servlet.
Path parameters, such as ;jsessionid=xxxx
, are not exposed, and you will need to parse the request URI to access them.
The request instance provides methods to access all aspects of the request URI used to identify the requested resource:
requestURI = contextPath + servletPath + pathInfo
The context path represents the web application specific prefix (for the default root context, this is empty), the servlet path represents the web.xml
servlet mapping that activated this request, and the path info is the remainder of the URI.
This object has methods that also let you query the protocol that has been used (for example, HTTP/1.1)
, the scheme (http, https
, or ftp)
, and whether the request arrived over a secure channel (for example, https)
.
When data is sent to the server in the request entity's body, say using a POST, you can bring other methods to bear that help you to determine the type and length of the content that was sent.
You can also help the servlet container parse the content correctly by setting the appropriate character encoding.
If you choose to, you can directly read the request body, either as a binary stream (using a ServletInputStream)
or using a reader, which applies the appropriate character conversions based on the character encoding in effect.
It is possible to query the request object for the IP address, host name, and port of the remote client computer. In addition, you can also obtain the host name and port of the server to which the client computer made the original request, and the IP address, host name, and the port number of the host on which the request was actually received.
HttpServletRequest
also allows you to access information that is specific to the HTTP protocol, such as request headers, session related information, and the request method. It also grants you access to any cookies that were set by the server on this client and which are now diligently being returned on each request from that client.
An HttpServletResponse
object represents a general HTTP response that was generated by the servlet, including the status code, any response headers, and the response entity body. This image depicts key aspects of the response interfaces within the Servlet API.

For efficiency considerations, a response may be buffered. You may write to it using a character oriented Writer
or a byte oriented ServletOutputStream
. You can also set the content type and length as appropriate.
Headers must be added to the response before the response is committed, in other words, before any part of the response has been flushed to the client.
This class supports convenience methods to send a redirect response, or an error response.
As we have seen before, HTTP is a stateless protocol. In other words, every connection stands by itself and is not aware of any previous connection that was established between the client and the server.
However, for any kind of web application to function, it is necessary for a conversation to be established between a given client and the server.
The Servlet API achieves this by using the concept of a session. A javax.servlet.http.HttpSession
instance is associated with a particular client, and a session identifier that represents this instance is transmitted to the client, either as a cookie or encoded onto a URL. When the next request from this client comes in, it is examined for either a cookie or a URL path parameter named jsessionid
that holds the session identifier that describes the conversation with this client. If this parameter is found, the server is able to associate conversational state with this new request.
The specific session tracking mechanism used is transparent to the user, and cookies will be used by default. URL rewriting, which requires that each URL generated must have the jsessionid
path parameter encoded into it, is used as a fallback mechanism.
It is interesting to note that sessions are scoped at the application context level. In other words, they are unique to a particular servlet context. If you forward a request to a servlet in another web application, then that servlet will use a session that is different from the session of the calling servlet.
Session scoped objects are particularly sensitive to multithreading issues. Care should be taken to ensure that any accesses to session attributes are done in a thread-safe manner, possibly by synchronizing on the user's session itself.
On the client, cookies are usually controlled by the web browser process and are not associated with any particular tab or window of the browser. As a result, requests from all the windows of a client application might be part of the same session. For maximum safety, you should always assume that this is the case.
Filters are web components that usually do not by themselves process requests. Instead, they are intended to act as assembly-line processors placed in front of the servlet. They pre-process the request, passing the request along to the next filter in line, until it finally arrives at the servlet, which does the actual processing. Then, the assembly line works in reverse, with each filter getting a chance to weigh in on the response that is generated by the servlet.
Any filter can short circuit the processing, simply by refusing to pass on the request and is then responsible for generating the response sent to the client.
The servlet container is responsible for instantiating the filters and deciding the order in which they must be invoked for a given request.
Filters are very selective, and you can configure them to be invoked for one or more of the following types of requests:
- Those that come directly from a client (the default)
- Those that arise out of a server-side forward, where one servlet hands off processing to another
- Those that arise out of an include, where one servlet delegates part of the processing to another servlet
- Those that arise when the error page mechanism is invoked
In all cases, the filter is invoked only if the web container finds a match between the URL-pattern or servlet name that is configured for that filter and the destination resource.
Event listeners are classes that implement one or more of the standard servlet event listener interfaces. For example, a class that implements the javax.servlet.ServletContextListener
interface will be notified when the servlet context has been started, and when the servlet context is about to be shut down.
Listener classes are declared in the web application's deployment descriptor. When the web application is deployed, the web container will automatically instantiate each listener that it finds in the deployment descriptor, and will register them with their subjects, according to the interfaces that they implement, and the order in which they appear in the deployment descriptor.
During web application execution, listeners are notified in the order of their registration.
Web applications
The web container makes the application available to the application's servlets in the form of a servlet context. In other words, a javax.servlet.ServletContext
instance represents a running web application within a container.
A web application is a collection of servlets, JSPs, utility classes, static content (HTML, CSS, images, and so on), and other resources along with an application deployment descriptor that are arranged in a structured hierarchy of directories.
The root of this directory hierarchy maps to the context path for this web application and also serves as the document root for the files that are part of this application.
For example, for an application whose context path is /products
, the file /index.html
, which is at this document root, can be accessed in a browser as /products/index.html
.
A special directory exists within this structured hierarchy named WEB-INF
. This directory and its contents are not part of the document root of the web application, and no file contained within it may be served to a client. Any requests to files within this directory will be met with a NOT_FOUND (404)
response. However, the contents of this folder are visible to server-side code.
The usual contents of WEB-INF
include the web application's deployment descriptor, web.xml
; a classes
folder, which contains the servlets and utility classes for this application; and a lib
folder, which contains the JAR files that are required by this application. As we will see in a later chapter, the class files in this folder are accessed using a special web application class loader that defies the laws of class loading, well at least those related to the standard delegation model. This class loader must load classes from WEB-INF\classes
first, and then from the JARs in WEB-INF\lib
.
Web applications may be packaged into a Web Archive Format (WAR) using the JAR tool. WAR files will usually have an additional META-INF
folder, which contains an optional context fragment as well as a manifest file. The contents of this folder also cannot be directly requested by a client.
Every web application must be accompanied by a deployment descriptor named web.xml
that is placed directly in the application's WEB-INF
folder. The root element in this document is named web-app
, and its sub elements can be in an arbitrary order.

Its primary purpose is to link the various elements that we've described so far into a harmonious whole. For instance, the<servlet>
element maps a fully qualified servlet class to a logical name that will be used to refer to that servlet. That logical name is then mapped using a servlet-mapping
element to a given URL pattern.
Its<filter>
element associates the fully qualified class name of a servlet filter with a logical name. This logical name can then be mapped to a given URL pattern or to a servlet's logical name using the filter-mapping
element.
Both servlets and filters can be initialized using parameters that are provided within the deployment descriptor.
A<context-param>
element lets you specify global servlet context initialization parameters, which are available to all servlets that run within this application context.
The<listener>
element defines the fully qualified name of a class that is to be registered as a web application event listener.
Another key element is<session-config>
, which lets you set the default session timeout interval for all sessions that are created in this web application.
Given its central role within a web application, we'll see a lot more of this deployment descriptor in later chapters. For now, this brief introduction should suffice.