by Steven J. Owens (unless otherwise attributed)
Since JSP is essentially a set of tools to make it easier to write servlets, I'm going to focus on servlets first, then on JSP. I highly recommend reading at least the Servlet Specification. It's very readable. You can get it here:
http://java.sun.com/products/servlet/reference/api/index.html
I think a lot of people miss the boat on what exactly a servlet is. If you like the nitty gritty, skip down to the next section, but you might be missing out.
At the blindingly obvious level, the Servlet specification is essentially a standard set of tools for developing web applications. But a servlet engine, when you come right down to it, is a program that:
The servlet engine keeps the instance in memory and routes future requests to the same instance, even simultaneously (if requests come in simultaneously). The exact details (what URLs lead to what servlet classes, etc) are usually controlled by a configuration, which is usually in an XML file (web.xml).
There are really two or three "big" topics under the umbrella of the servlet spec.
I think the servlet engine concept is where you should start, but almost everything else I've seen on this topic gets bogged down in hyping the concept. I'm going to assume you've gotten about a page into a half-dozen of these articles and are sick of the servlet engine concept. So for now I'm going to leave it at the short description above, and dive right into the classes.
"Getting" the idea of the servlet engine is important, however, so if you're not sure about the general servlet engine concept, go back to the overview and read it, then come back here.
The Servlet Spec defines a number of standard classes and how they're normally expected to interact. This provides a handy framework or set of tools for building a web application. I'm going to list what I think are the most important classes in the servlet API, grouped according to a combination of how I think you'll tend to use them and a hand-wavy "underlying nature" I think the different pieces share. In a sense, each group is a sort of dimension of the servlet spec. When these four dimensions come together, you have a complex and (somewhat) elegant tool for solving a large problem space.
Overuse of Bold Text Alert The first time I wrote this section, I had several key phrases in bold, like "the servlet class does not get instantiated freshly for each HTTP request" and "any servlet must be coded to be either stateless or thread-safe". Then I took another look at it and decided it looked sort of like a used car commerical: "Down here at Crazy Eddie's used car lot, our prices are insane!"
So I took the bolding out and I'll just tell you, there are some really important stumbling blocks that I talk about here, so read this section carefully. I mean, carefully.
The Servlet Stuff are the classes most directly involved with speaking HTTP and dealing with URLs and redirects and the like.
People tend to get sloppy with the noun "servlet". Explaining this stuff would be easier if we had specific words for phrases like "servlet class" and "servlet instance". Most importantly, there's no correct, commonly-used phrase for the most blatant aspect of all, what I'll call the mapping. The mapping defined by configuration entry, usually in the webapp's web.xml file, which maps a URL pattern to a specific instantiation of a specific class.
I think the mapping is one of the most important concepts to keep in mind, because it's easier to keep clear about what's going on if you keep the arbitrary URL-to-instance mapping in the forefront, because that's the essential nature of a servlet - an entry point into the JVM.
The HttpServlet class defines a superclass for your servlet class; the servlet class is the class you develop, that the servlet engine will instantiate and keep in memory, and, according to the URL pattern you define in the configuration file, route HTTP requests to.
Note: Strictly speaking, a servlet doesn't have to be HTTP-oriented (just have your servlet descend from javax.servlet.GenericServlet instead of HttpServlet) but almost nobody does that and the general concept of non-HTTP servlets has been greatly de-emphasized since the servlet spec first came out.
An important stumbling block for beginning servlet developers is that the servlet class does not get instantiated freshly for each HTTP request. At first glance you would think this would be the "proper" OO thing to do, but it's not. It seems like the proper OO thing would be an instance per request, if you think of the servlet as modeling the request handler. But it's not, it's modeling the entry point into the application. It's up to you, in your servlet code, to figure out what handler classes need to be instantiated and/or invoked.
Instead, the servlet engine will instantiate a single servlet instance per configured servlet, and keep it in memory to answer multiple subsequent requests, sometimes simultaneously. What this means is that every servlet must be coded to be either stateless or thread-safe. Any user state should generally go on the HttpSession (see the next section) or elsewhere in the application.
Note: You can, of course, configure more than one mapping per servlet class file. Each mapping will get its own single instance of that class, which will each have to deal with its own set of possibly-simultaneous requests. This really only makes sense if you use parameters - defined in the same place you define the mapping - to cause different behavior between the two servlet instances.
The HttpServletRequest and HttpServletResponse model the HTTP request and response. These objects take care of things like parsing any request parameters and cookies, and formatting any response headers. The servlet engine parses each HTTP request, sets up a pair of HttpServletRequest and HttpServletResponse objects, and passes them in to an HttpServlet's doGet() or doPost() method.
Unlike the servlet instance, you get a fresh request and response instance for each browser request. However, you should avoid hanging onto references to the requests and responses past the servlet invocation. The servlet engine will produce the request and response instances and may be pooling and reusing them or otherwise doing odd stuff with them. Also, each request or response will have references to a lot of stuff, that might otherwise be ordinarily garbage-collected. In general they're meant to be ephemeral objects. For persistence, see the Session Stuff, below.
HttpRequestDispatcher is a sort of oddball class, it's a traffic cop that you you use for server-side includes and forwards. An include transfers control of the request and response temporarily to another servlet. When the dispatched-to servlet's doFoo() method returns back to the request dispatcher, the request dispatcher in turn returns back to the servlet (or other class) that called the request dispatcher. A forward transfers control permanently - when the dispatched-to servlet's doFoo() method returns, the client connection is closed and the request dispatcher never returns control back to the calling servlet.
The Session Stuff is all about keeping track of semi-persistent data at the server side. Any really persistent stuff should go into a database, but the session stuff makes it convenient to keep objects in memory in between browser requests. They're also the tools you use to share data between different pieces of your web application.
Note: This gives you a lot better performance, not to mention cleaner code, than pulling stuff out of the database and jamming it back in for every HTTP request. However, bear in mind the tradeoff that every object instance you stash in the session also increases the total in-memory overhead of your application.
The session is basically a Hashtable of references to objects that you created in earlier servlet invocations and stashed in the session. The servlet engine manages the session for you; making sure a given user has a JSESSIONID cookie, keeping track of the server-side objects associated with that JSESSIONID, and making it easy for you to get a reference to the session via the HttpServletRequest's getSession() method (in fact, that's almost the only way to get a user's session).
Note: The servlet spec also provides some tools for coping if you need to support users with browsers that don't do cookies (for whatever reason). In a nutshell, when generating each web page, you run every webapp link or URL through an encoding method that inserts the JSESSIONID in the URL.
The ServletContext is the webapp-wide version of the session. It's where you stick values that you want to make available to other users in the same session. I don't find I use it very often, because by the time data's ready to be shared webapp-wide, it's also usually in a database, where there are more powerful tools for finding it and displaying it.
Besides HttpSession and ServletContext, you can also stash stuff (very) temporarily on the HttpServletRequest. This is what you use to pass data around between servlets when using server-side includes or forwards via the RequestDispatcher. The request only lives a short while, for the life of the HTTP request/response cycle, basically.
I also included the request.getRemoteUser() and request.getUserPrincipal() methods in this section, because in a sense, the user's authenticated identity is an aspect of the user session (and an important aspect!).
The Filter Stuff provides a useful and general tool for a fairly narrowly scoped problem.
A filter is sort of a mutant servlet; like a servlet, it gets configured with a URL pattern that it's responsible for. However, the assumption with a filter is that it's going to intercept a browser request on the way in, or the servlet engine's response on the way out, or both, and do something to it. This is where the HttpServletRequestWrapper and HttpServletResponseWrapper come in. They're convenient classes to extend so you can wrap a given request and/or response in your customized class that does something useful. (This doesn't mean that you have to be inside a filter to use the wrappers, you can use them like any class).
Note: One important difference between a Filter and an HttpServlet is that Filter is an interface, not a superclass. There's no partial implementation provided the way there is for HttpServlet.
Note: Like a servlet, a filter is not something your code should ever directly worry about instantiating or configuring. Instead, you handle that with a configuration entry in the webapp's web.xml.
Filters are sort of odd ducks. They're for a specific need, but when you need 'em, you need 'em (or something like them). My old martial arts instructor used to use the analogy of a screwdriver versus a pipe-cutter. You can use a screwdriver for a lot of things besides driving screws: prying paint cans open, punching holes in cardboard, etc. A pipecutter doesn't do as many things, but when you need to cut pipe... you need a pipecutter.
The funny thing is, I've never really heard all that many good examples of other uses for filters, besides the two I'm about to describe. Other examples I've seen seem really contrived, like editing out blink tags, or compressing output before sending it back to the browser.
The classic examples for filters are authentication and header-setting. Header setting is fairly easy to understand - make sure that all responses have a no-cache header set on them, for example. Authentication filters usually check to make sure the user's logged in, and if not, redirects them to a login page. There's a J2EE standardized piece of the servlet API to do this (google on J2EE Form Authentication) but it has some annoying design quirks and a lot of folks just skip right past it and develop a filter, or use the fairly popular package securityfilter.
The Listeners are similar to filters and servlets:
Listeners get invoked, for example:
I'd like to give you some good examples of uses for listeners here, but frankly I've never found a really good use for them. One use that came to mind was tracking when a user session is created and destroyed, but that didn't seem important enough to use a listener for. Then again, maybe it doesn't really have to be that important to justify it. I may be unconsciously equating Listeners with the Servlet level of granularity, when it really wouldn't be a big deal at all to use a listener for that sort of thing.