Filter vs OncePerRequestFilter in Spring Boot – Full Breakdown with Real Example

 

When building Spring Boot applications, intercepting HTTP requests is a common requirement — for authentication, logging, or preprocessing. Two tools often used for this purpose are:

  • Filter (from the Servlet API)

  • OncePerRequestFilter (provided by Spring)

They may seem interchangeable, but they behave very differently in real-world scenarios. This blog will guide you through their differences, show how chain.doFilter() works, and provide a live example.


What is a Filter?

A Filter is part of the Java Servlet API (jakarta.servlet.Filter). It allows you to intercept requests before they hit your controller.

🔍 Key Points:

  • Can execute multiple times for the same logical request

  • Executes for all types of dispatches: REQUEST, FORWARD, INCLUDE, ERROR

  • Ideal for generic request modifications or logging at the servlet container level


What is OncePerRequestFilter?

OncePerRequestFilter is a Spring Framework utility (org.springframework.web.filter.OncePerRequestFilter) that ensures the filter logic is invoked only once per request lifecycle, even if the request is forwarded or included.

🔍 Key Points:

  • Executes only once per request

  • Ignores FORWARD, INCLUDE, and ERROR dispatches by default

  • Best suited for authentication, JWT validation, rate limiting


What Does chain.doFilter() Do?

Within any filter, the line:

java
chain.doFilter(request, response);

means:

“Pass control to the next filter in the chain or ultimately to the controller if no filters remain.”

If you don’t call chain.doFilter(), the request will not proceed any further. You can short-circuit the request (e.g., return 401 Unauthorized).


Let's See the Difference in Action

We’ll build a Spring Boot setup with:

  • A standard Filter

  • A OncePerRequestFilter

  • A controller that forwards one endpoint to another


1. StandardFilter.java

java
@Component public class StandardFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; System.out.println("StandardFilter executed for URI: " + req.getRequestURI()); chain.doFilter(request, response); } }

2. CustomOnceFilter.java

java
@Component public class CustomOnceFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { System.out.println("OncePerRequestFilter executed for URI: " + request.getRequestURI()); filterChain.doFilter(request, response); } }

3. DemoController.java

java
@Controller public class DemoController { @GetMapping("/entry") public String entry(HttpServletRequest request) throws ServletException, IOException { System.out.println("Inside /entry controller"); request.getRequestDispatcher("/final").forward(request, request.getServletResponse()); return null; } @GetMapping("/final") public String finalHandler() { System.out.println("Inside /final controller"); return "done"; } }

Output When Accessing /entry

text
StandardFilter executed for URI: /entry OncePerRequestFilter executed for URI: /entry Inside /entry controller StandardFilter executed for URI: /final Inside /final controller

☝️ Notice: OncePerRequestFilter does not run again for /final, but StandardFilter does.


Comparison Table

FeatureFilterOncePerRequestFilter
API SourceServlet API (jakarta.servlet)Spring Web (org.springframework)
Runs for FORWARD/INCLUDE✅ Yes❌ No
Executes only once per request❌ No✅ Yes
Best forLow-level container tasksApp-level logic (auth, JWT, etc.)
Requires extra config?❌ No❌ No

When Should You Use Each?

Use Case Recommended Filter Type
Simple logging for all requests Filter
Authentication, JWT validation OncePerRequestFilter
Rate limiting or custom headers OncePerRequestFilter
Static resource filtering Filter

Final Recommendation

If you're building Spring Boot REST APIs and want to add logic like token validation, logging, or rate-limiting — go for OncePerRequestFilter. It's Spring-friendly, clean, and avoids surprises like multiple executions during forwards.

Only use the plain Filter when dealing with servlet-level tasks or need fine-grained control over dispatch types.

Post a Comment

0 Comments