In software development there is a big number of cases when you need somehow to catch a request coming to server and do some pre-processing or post-processing. For example, it is must for authentication, when you need to validate if user was granted to access the specific path before this path’s execution. Spring provides as a part of Spring Web a way to do it – using SpringInterceptor
objects. They allow to do provide a custom logic before or after controller processes a handler.
This post describes a definition of Spring’s HandlerInterceptor, how it is different from Java Servlet’s HttpFilters, as well an overview of HandlerInterceptor
interface methods and how to configure them in your applications.
What is Spring HanlderInterceptor?
HandlerInterceptor is a Spring Web interface, that allows to implement components to intercept client requests and to provide a custom processing logic. Such processing can be executed prior or after Spring controllers process requests. Handler interceptors implement org.springframework.web.servlet.HandlerInterceptor
interface that offers three core methods:
boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler)
void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler, ModelAndView mw)
void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex)
Developers can register any number of interceptors, as well attach them to specific group of handlers and control their order. Such functionality relates HandlerInterceptors with another tool – HttpFilters.
Creation of HandlerInterceptor
As it was mentioned, in order to create an interceptor, developer has to implement HanlderInterceptor
interface. As all its methods are default, you can provide implementation for all of them or only for the needed one. HanlderInterceptor are often used to implement token-based authentication. Let have a look on a basic case of using HandlerInterceptor
:
@Component public class TokenInterceptor implements HandlerInterceptor { @Autowired private AuthService service; @Override public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception { String authToken = req.getHeader("Authorization"); if (authToken==null) throw new RuntimeException(); return service.validateToken(authToken); } }
In this code snippet we created a custom interceptor component to check that incoming requests do have valid authentication token attached. Please note, that unlike HttpFilters, HandlerInterceptor provide an access to HttpServletRequest
and HttpServletResponse
components, so you can use them directly without necessity to cast from ServletRequest
and ServletResponse
.
We also annotated TokenInterceptor
class as Spring’s @Component
to make the framework know to treat it in this manner in annotation-based configuration.
Interface methods
The interface provides three default methods. This section provides an overview of them.
preHandle()
This method intercepts an execution of the request handling. It is fired before controllers process the request and returns a boolean value, that is used to determine next processing. If true is returned by preHandle()
method, then request goes to handler. In case of false return, request is interrupted. This method accepts three arguments:
HttpServletRequest
is a current HTTP requestHttpServletResponse
is a current HTTP responseHandler
is the chosen handler object to handle the request
As we talked before, this method can be used to validate pre-conditions, such as tokens. We also can pass information to handlers using HttpServletRequest
. Take a look on the code snippet below:
@Override public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception { String token = req.getHeader("Authorization"); Optional<User> user = service.parseToken(token); if (user.isPresent()){ req.setAttribute("user", user.get()); return true; } else { return false; } }
postHandle()
This method is fired after handler processing by Spring controllers, but before rendering the view (if you build an application, that follows MVC architecture). So in this case you can modify the ModelAndView
that is going to be displayed and attach additional data. This method accepts four arguments:
HttpServletRequest
is a current HTTP requestHttpServletResponse
is a current HTTP responseHandler
is the chosen handler object to handle the requestModelAndView
is the returned by the handler ModelAndView object.
As an example of using such method we can provide a situation, when we want to display to the user a time used to render a page. For this we also need first to capture an initial timing using preHandle
. Take a look on the following snippet:
@Override public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception { long started = System.currentTimeMillis(); req.setAttribute("startedTime", started); return true; } @Override public void postHandle postHandle(HttpServletRequest req, HttpServletResponse res, Object handler, ModelAndView modelAndView) throws Exception { long started = Long.valueOf(req.getAttribute("startedTime").toString()); long finished = System.currentTimeMillis(); long rendered = finished - started; modelAndView.addObject("renderedTime", rendered); }
afterCompletion()
Finally, the third method here – afterCompletion()
is called after handler was processed and after view was rendered to the user. Please note, that this method is called at any case of handler execution, but only if the corresponding preHandle()
method returned true. It accepts four arguments:
HttpServletRequest
is a current HTTP requestHttpServletResponse
is a current HTTP responseHandler
is the chosen handler object to handle the requestException
is an exception thrown by handler, unless, it was handled through an exception resolver
We can use such method to log result of handler processing like in the following code:
// assume we have a logger private static final Logger logger = LoggerFactory.getLogger(SampleInterceptor.class); @Override public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) throws Exception{ String destination = req.getRequestUrl(); int result = res.getStatus(); logger.info("The request to the destination {} was processed with the result {}", destination, result); }
Configuration
In order to use the handler interceptor we need to configure it using a custom instance of WebMvcConfigurer
configuration. Here is a code that demonstrates a basic usage of token interceptor configuration:
@Configuration public class TokenInterceptorConfig implements WebMvcConfigurer { @Autowired private TokenInterceptor tokenInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(tokenInterceptor); } }
This code attachs the interceptor to all handlers. We also annotated it with Spring’s @Configuration
to tell the framework that it is used to define beans and Spring container will use in bean generation. Although, this is the basic case. We also can:
- Attach interceptors to specific routes/groups of routes
- Exclude interceptors from specific routes/groups of routes
- Define an order of interceptors execution
For this we need to manipulate InterceptorRegistration
object returned as a result of addInterceptor()
.
Include paths
To attach interceptors for specific paths or groups of routes we can utilize addPathPatterns()
method that allows to specify certain paths. It comes in two overloaded versions:
addPathPatterns(List<String> patterns)
that accepts a group of patterns in a form of the array listaddPathPatterns(String... patterns)
that accepts patterns in a form of varagrs
As we have a token interceptor, we want to apply it to all routes that starts with /secured/
:
@Override public void addInterceptors(InterceptorRegistry registry){ registry.addInterceptor(tokenInterceptor).addPathPatterns("/secured/**"); }
In this code snippet, we use here double asterisk to tell Spring to include paths
Exclude paths
Similarly, we can exclude some paths from using the interceptor. It can be done using excludePathPatterns()
method, which can be in two forms:
excludePathPatterns(List<String> patterns)
that accepts patterns in form of listexcludePathPatterns(String... patterns)
that accepts patterns as varargs
For instance we want to exclude paths /login
, /signup
and /restore-password
from token validation (as they don’t yet have any security):
@Override public void addInterceptors(InterceptorRegistry registry){ List<String> excludedRoutes = Arrays.asList("/login", "/signup", "/restore-password"); registry.addInterceptor(tokenInterceptor).addPathPatterns("/secured/**").excludePathPatterns(excludedRoutes); }
Define order
Finally, if we use several HandlerInterceptors we can specify an order they are executed. This is done by calling order()
method from InterceptorRegistration
that accepts an int number of interceptor’s order (started from 0). For instance we have three interceptors: one to validate tokens, second to validate user’s subscription status and finally to log:
@Configuration public class AppInterceptorConfig implements WebMvcConfigurer { //.. inject interceptors @Autowired private TokenInterceptor tokenInterceptor; @Autowired private SubscriptionInterceptor subscriptionInterceptor; @Autowired private LoggingInterceptor logInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(tokenInterceptor).order(0); registry.addInterceptor(subscriptionInterceptor).order(1); registry.addInterceptor(logInterceptor).order(2); } }
Conclusion
In this post we looked on Spring Web’s HandlerInterceptor
interface that is used to intercept client requests and to provide a custom processing logic. We also compared it with a similar tool – HttpFilter
that comes from JavaEE and is independent from Spring. We validated methods that this interface provides as well how to configure it for usage in Spring apps.

Do you want to increase your Java collections skills?
This topic is really huge, and a single post is not enough to cover all. That is why I wrote this Practical Guide. Everything you need in the one book. Do you want to become Java ninja?
References
- Iuliana Cosmina et. all Pro Spring 5 5th edn, Apress, 2017
- The Essentials of Filters Oracle Technology Network, read here