As you start out building Java web applications, you soon find that it sit upon several well designed building blocks. Once the penny drops, and an intuition about these building blocks is gained, creating web apps on Java becomes a delight.
Two key, top level concepts are the mighty Servlet API and JavaServer Pages (JSP). These are deployed to a Web container, also commonly referred to a Servlet (or Web) container.
The Servlet container, a vendor neutral bubble, provides several well defined subsystems and interfaces (knobs and dials) as defined by the Java specification. The container provides the underlying plumbing for services such as request dispatching, life cycle management, session management and security for example.
- Configuration (web.xml)
- The Servlet API
Here’s a sample web application development structure made by Eclipse.
. ├── src │ └── net │ └── bencode │ └── servlet │ └── PopServlet.java └── WebContent ├── css │ └── app.css ├── img │ └── hero.png ├── index.jsp ├── js │ ├── app.js │ └── jquery.min.js ├── META-INF │ └── MANIFEST.MF └── WEB-INF ├── lib └── web.xml
Web Application Archive (WAR)
war is the neatly packaged deployment bundle, ready to be slotted into a web container.
Web applications can be deployed either as an assembled
war file, or as an unpacked (or exploded) directory tree following the same tree layout.
Given the above sample development tree, here’s the corresponding WAR layout. Notice how bytecode (
class files) and library dependencies (
jar files) are neatly packaged under
. ├── css │ └── app.css ├── index.jsp ├── js │ ├── app.js │ └── jquery.min.js ├── META-INF │ └── MANIFEST.MF └── WEB-INF ├── classes │ └── net │ └── bencode │ └── servlet │ └── PopServlet.class ├── lib │ ├── joda-time-2.9.1.jar │ └── slf4j-api-1.7.12.jar └── web.xml
Also note how static web content (e.g. html, images, css, js) are simply placed into the root of the structure.
Assuming you have a tree layout that conforms, assembling a
war is simple. In fact, as for a
jar, its nothing more than a compressed archive. Therefore in the root directory of the web application, to assemble yourself a
war, could run:
jar cfv fun.war .
web.xml is also commonly referred to as the web application deployment descriptor, and from a birds eye view looks like this:
- Alias Paths - the most important, defines addressing needs.
- Context and initialisation parameters
- Event listeners
- Filter mappings
- Error mappings
- Environment and Resource references
web.xml is a little touchy. Not only is it case sensative, its elements are order sensative. Configuration element should appear in the following order:
Maps out what web components will serve what specific HTTP requests.
Context and initialisation parameters
Represents an application context for all web components, within the same
Using the context is simple:
In addition to global context level parameters, servlet scoped initialisation parameters defined in the deployment descriptor (
web.xml) are accessable in the
The Servlet API
A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP.
GenericServlet is the base class that all protocol specific implementation, such as
HttpServlet inherit from. GenericServlet’s
service method is responsible for implementing protocol related plumbing, and dispatching to hooks such as
doPut in the case of
An example HTTP Servlet by extending
HTTP parameters (from either an HTTP
POST event) are parsed and made conveniently available through
HttpServletRequest attributes provide a way for the Servlet container to make available additional information about a request. For example, the
javax.servlet.request.X509Certificate attribute for HTTPS.
Also a useful temporary place to stick state that will live for only the request/repsonse cycle, by calling
setAttribute. For example, possibly useful for communicating between multiple Servlets.
Includes are useful for injecting the content generated by another Servlet/JSP. While includes can write to the response output stream, they are unable to modify other aspects of the response such as headers and cookies for example.
Forwarding is a server side concept, where one Servlet completely delegates to another Servlet. From the clients point of view, the original resource they requested comes back as a result, and is none the wiser that a chain of server side forwards may have occured in order to accomplish the rendering.
Forwarding can be useful in pre-processing scenarios, i.e. where one Servlet might perform some function, and then hand over to another Servlet to take care of generating the response.
A great example that server-side forwarding enables, is the dispatcher pattern, for applying a common set of pre-processing a request or response. In the below example, a master page (a common template to be applied to all responses) is implemented as a dispatcher.
First the Servlet:
All requests are poored through
template.jsp, which applies a common layout. In the deployment descriptor (
web.xml), all requested with the
*.ben suffix are configured to go through the dispatcher. The dispatcher then removes the
.ben extension, and stores this in request scope, so later on
template.jsp can do an include.
An HTTP request such as
http://localhost:8080/app/logs.ben will result in
template.jsp being rendered, with an include to
/logs (which may for example be a static resource, Servlet or JSP). Not too shabby.
response.setStatus(response.SC_MOVED_PERMANENTLY); response.setHeader("Location", "http://slashdot.org");
Lifecycle Event Listeners
Allows a Servlet to be notified of interesting events that occur within the container, such as
ServletContext startup/shutdown and attribute changes,
HttpSession creation and modifications.
ServletContextListener: hooks for
ServletContextAttributeListener: hooks for
HttpSessionListener: hooks for
HttpSessionBindingListener: causes an object to be notified when it is bound to or unbound from a session, with
HttpSessionAttributeListener: hooks for
HttpSessionActivationListener: hooks for
sessionDidActivate. When the container either migrates a session between JVMs or persists sessions.
Here’s the stub for a ServletContext Listener:
Then bind it in the deployment descriptor:
A servlet filter is a flow through component that allow some code to (transparently) execute within the servlet request/response pipeline. A logging filter, for example, might log the details of HTTP requests into a database. This section of the deployment descriptor, maps which filters are applied to requests, and in what sequence. This can also be achieved using the
Browsers and devices can indicate a language preference to the server, as the
POST /ben-on-mvn/fruit/summer/watermelon HTTP/1.1 Host: localhost:8080 Connection: keep-alive Content-Length: 41 Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Origin: http://localhost:8080 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36 Content-Type: application/x-www-form-urlencoded Referer: http://localhost:8080/ben-on-mvn/index.jsp Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.8 Cookie: JSESSIONID=B775CE728B750AFC4EF89C4CCEC9C853
To see this in action, throw a couple of
properties files into
src/main/resources, so Maven will know to bundle them into the
You’ll see the Locale API plays nicely with Servlets:
├── css │ ├── app.css │ ├── foundation.css │ └── foundation.min.css ├── index.jsp ├── js │ ├── app.js │ ├── foundation.js │ ├── foundation.min.js │ └── vendor │ ├── jquery.min.js │ └── what-input.min.js ├── META-INF │ └── MANIFEST.MF └── WEB-INF ├── classes │ ├── messages_en_US.properties │ ├── messages.properties │ └── net │ └── bencode │ ├── app │ │ └── Application.class │ ├── filter │ │ └── FunFilter.class │ └── servlet │ ├── DrPepperServlet.class │ ├── PopServlet.class │ └── WatermelonServlet.class ├── lib │ └── joda-time-2.9.1.jar └── web.xml
By default, a single
Servlet instance can be invoked by many request threads. Therefore it’s important to protect the
_service() method from the family of issues that can arise from multi-threading, such as race conditions, dead locks, and inconsistent state.
Common approaches to Servlet synchronisation:
Guarantees only a single thread can access a section of code.
Servlets can also implement
javax.servlet.SingleThreadModel. This will instruct the servlet container to allocate a pool of instances of the servlet, assigning a dedicated instance to each request thread.
Warning: Due to poor design, this interface has been deprecated, and should no longer be used. I’m listing it here, because I still come across them in the wild.
SingleThreadModel does not solve all thread safety issues. For example, session attributes and static variables can still be accessed by multiple requests on multiple threads at the same time, even when SingleThreadModel servlets are used.
Instead remove state, so that the same servlet can be used by multiple threads concurrently.
Three methods of tracking a session identifier to a stateless HTTP client; cookies, URL rewriting and/or hidden form fields.
- Cookies: persistent across browser shutdowns, might not be available.
- URL Rewriting: involves recrafting the URL (with
encodeURL) specific to each consumer like this
http://foo.com/servlet?session=1337. Ubiquitous, only works for dynamic pages.
- Hidden form fields:
<input type="hidden" name="session" value="1337" />. Same benefits and shortfalls as URL rewriting.
The servlet API provides a session abstraction called
HttpSession to manipulate the session identifer, creation time, last accessed time, and store objects.
Sessions can be explicitly cleaned up (i.e. not by waiting for a timeout) by calling