A filter object can process the request to and the response from a servlet. Unlike a servlet, a filter does not typically interpret the request or create the content of the response. Instead, a filter can process the request and response objects either before or after the request reaches the servlet. For example, a filter might translate an XML response into HTML.
The servlet container constructs a sequence of filters for each servlet. The sequence is called a filter chain. A filter chain provides a function that dispatches a request to the next filter in the chain, or to the servlet itself if there are no more filters in the chain.
When a client request arrives for a servlet, the servlet container determines whether any filters are declared for that servlet. If not, the container forwards the request directly to the servlet. If filters are declared, the servlet container constructs a filter chain and calls the dispatch function of the chain. The first filter in the chain receives the request, processes it, and then calls the dispatch function on the chain. The chain dispatches the request to the next filter in the chain. After the servlet creates a response, the dispatch function call in the last filter on the chain returns. The filter processes the response, then returns. The dispatch function call in the next-to-last filter in the chain returns, that filter processes the response, and returns. The process continues until the response returns to the servlet container.
The diagram below shows a typical filter chain. Each filter in the chain uses the doFilter() function of the chain to invoke the next filter, or the servlet itself at the end of the chain. As each function returns, control returns back through the chain. After all functions in the chain return, the response returns to the container, and the container sends the response back to the client.
Figure 2 – Filter chain
Since each filter must explicitly invoke the next object on the chain, a filter can deny access to a servlet by simply returning without calling doFilter() on the chain. Figure 3 illustrates a filter chain refusing a request. The second filter on the chain explicitly calls return without calling doFilter(). In this case, the response returns to the container without the request ever reaching the servlet.
Figure 3 – Filter chain with access control
Filters efficiently encapsulate message preprocessing and postprocessing. A filter can process requests for any number of servlets, and because the filter is multithreaded, it can handle more than one request simultaneously. No servlet need duplicate the processing code the filter contains, or even be aware of the filter.