skip to content

Chain of Responsibility in Java

Servlet filter chains are Chain of Responsibility in production: each doFilter either handles the request or passes it down the configured order. Any interview touching Spring Security or servlet plumbing eventually lands here.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

What is the Chain of Responsibility pattern, and how do Servlet Filters embody it?

level: juniorimportance: must knowfreq 70%

answer

  1. Handlers in a line; each handles or delegates
  2. doFilter(request, response, chain)
  3. chain.doFilter() = pass to next; omit it = stop
  4. Before + after hooks (nested/onion)
  5. Decouples sender from receiver

basics

~20 s

It is a design pattern where a request passes through a series of handlers, and each one decides whether to process it or pass it along. Servlet Filters are a chain: each filter can act on a request, then call the next one.

solid answer

~40 s

Chain of Responsibility decouples the sender of a request from its receiver by giving multiple handler objects a chance to process it. Each handler holds a reference to the next; it either handles the request and stops, or delegates onward. Servlet Filters are the classic Java example: the container assembles configured filters into a FilterChain, and each Filter.doFilter receives the request, response, and the chain. A filter can run logic before and after the rest of the chain, and calls chain.doFilter(request, response) to pass control to the next filter, eventually reaching the target servlet. If a filter does not call chain.doFilter, the request stops there. This lets you add cross-cutting concerns like logging, auth, compression, or CORS without modifying the servlet, and reorder or remove them independently.

go deeper

for a junior

Can state that a request flows through handlers and each either handles it or passes it on, and recognize Servlet Filters as an example with doFilter and chain.doFilter.

for a middle

Explains the before/after (nested) execution model, the pass-through semantics of calling vs. omitting chain.doFilter, and gives concrete filter use-cases.

for a senior

Relates the pattern's intent (decouple sender from receiver, compose cross-cutting concerns) to the Filter API design, and discusses ordering and short-circuiting trade-offs.

for a principal

Frames filters within the broader interception architecture (filters vs. Spring HandlerInterceptors vs. AOP), reasons about where each concern belongs, and the lifecycle/threading implications.

### The problem Imagine an HTTP request arriving at a web server. Before your actual business code (the *servlet*) runs, you often want several independent things to happen: log the request, check authentication, validate input, set CORS headers, compress the response, and so on. You do **not** want to cram all of that into one giant method, because each concern changes for different reasons and you want to add, remove, or reorder them freely. ### The pattern **Chain of Responsibility** is one of the original "Gang of Four" design patterns. The idea: instead of one object handling a request, you arrange a **chain of handler objects**. The request is given to the first handler. Each handler does one of: - **Handle it fully** and stop the chain, or - **Do part of the work and pass it on** to the next handler, or - **Ignore it and pass it on** unchanged. The *sender* of the request does not know which handler will deal with it — it just hands it to the front of the chain. This **decouples** sender from receiver and lets you change the set of handlers without touching the sender. ### Key terms - **Handler**: an object with a method that takes the request and a reference to "the rest of the chain." - **Delegation / pass-through**: a handler calling the next handler in line. - **Cross-cutting concern**: logic (logging, security) that applies to many requests regardless of business meaning. ### Servlet Filters: the Java/Jakarta embodiment A **Servlet** is a Java object that handles HTTP requests in a web container (Tomcat, Jetty). A **Filter** (interface `jakarta.servlet.Filter`, formerly `javax.servlet.Filter`) is an interceptor that runs *before and after* a servlet. Its single method is: ```java void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) ``` The `FilterChain` object **is** the "reference to the rest of the chain." When the container receives a request, it builds a `FilterChain` from all filters mapped to that URL (in configured order), with the target servlet at the very end. It invokes the first filter's `doFilter`. Inside, the filter typically: 1. Runs *pre-processing* logic (e.g. record start time). 2. Calls `chain.doFilter(request, response)` to invoke the **next** filter — or the servlet, if it is last. 3. Runs *post-processing* logic after that call returns (e.g. log elapsed time), because the call is synchronous and the rest of the chain runs nested inside it. This nesting means a filter wraps the entire downstream chain, giving it both a "before" and an "after" hook — like an onion of nested calls. ### Pass-through semantics If a filter **does not** call `chain.doFilter`, the request **stops** there — nothing downstream runs. That is exactly how an auth filter rejects an unauthenticated request: it writes a 401 response and simply returns without delegating. So calling (or not calling) `chain.doFilter` is the chain's control mechanism. ### Why it matters You can add logging, security, compression, or CORS as independent filters, configure their order, and enable/disable them per URL — all without changing the servlet. That is Chain of Responsibility delivering exactly its promised benefit.

  • What happens if a filter never calls chain.doFilter()?
    The request stops at that filter; no downstream filter or the servlet runs. The filter is responsible for producing the response itself (e.g. a 401 or a redirect).
  • Name two real cross-cutting concerns commonly implemented as filters.
    Authentication/authorization and request/response logging; also compression, CORS, character-encoding, and rate limiting.

saying these in an interview costs you the question

  • Saying every filter must handle the request — handlers may just pass it on
  • Confusing Filter with Servlet (filter intercepts; servlet is the endpoint)
  • Thinking the chain is parallel — it is synchronous, nested calls
  • Claiming you cannot run code after the chain returns — you can (post-processing)

context

open as a page

How is the order of Servlet Filters determined, and why does order matter?

level: middleimportance: should knowfreq 60%

basics

~20 s

In web.xml, filter order follows the order of the <filter-mapping> elements. With annotations or Spring, you set order explicitly (e.g. @Order or a FilterRegistrationBean). Order matters because earlier filters can short-circuit or change the request before later ones see it.

open as a page

Write a Servlet Filter that logs request method/URI and elapsed time, and explain the before/after structure.

level: middleimportance: should knowfreq 50%

basics

~20 s

Implement Filter.doFilter: record the start time, call chain.doFilter to run the rest of the chain, then in a finally block compute elapsed time and log the method, URI, and duration. The code before the call is pre-processing; the code after is post-processing.

open as a page

How does a Servlet Filter short-circuit the chain, and what are correct practices when doing so?

level: seniorimportance: should knowfreq 55%

basics

~20 s

A filter short-circuits by not calling chain.doFilter and instead producing the response itself — for example writing a 401 or sending a redirect. Then no later filter or the servlet runs. You must fully complete the response and not commit it twice.

open as a page

Compare Servlet Filters with Spring HandlerInterceptors as implementations of Chain of Responsibility. When would you choose each?

level: principalimportance: nice to knowfreq 40%

basics

~20 s

Both let you run code around a request in a chain. Filters live in the servlet container and see every request (even static files), working with raw request/response. Spring HandlerInterceptors live inside Spring MVC and know which controller/handler will run. Use filters for low-level/global concerns, interceptors for MVC-aware logic.

open as a page