Handler interceptors in Spring

Standard way of catching HTTP request in Java's web applications is the use of filters. But they are reserved only for webapps. Spring introduces a new way to do it, more general, called handler interceptors.

This article will be cut in 3 parts. The first one presents theoretical concepts of Spring handler interceptors. In the next one, we'll discover default Spring interceptors. The last part will be dedicated to more practical part and we'll write here our own handler interceptor.

What is handler interceptor in Spring ?

To good understand the role of Spring interceptors, we need to start by explain the execution chain of HTTP request. Every request is captured by DispatcherServlet. The first thing made by dispatcher is the mapping between received URL and controller which must handle current request. But the request, before arriving to appropriate controller, can be treated by interceptors. These interceptors are like the filters. They are invoked only when the URL corresponds to theirs mapping. After this optional treatment by interceptors (pre-interceptors), the request arrives finally to controller. After that, the request is send to generate the view. But before, the interceptors have a new possibility to deal with it (post-interceptors). Only after this last manipulation possible, view resolver can capture the data and output the view.

Handler mapping interceptors are based on org.springframework.web.servlet.HandlerInterceptor interface. As you saw in short description previously, they can intercept a request before sending it into controller (method preHandle) or directly after (method postHandle). preHandle method returns a boolean and can, if it returns false, interrupt request processing in the execution chain. An third method exists, afterCompletion, and it's invoked after rendering the view, only when the preHandler method sent true.

Interceptors can also be launched in new thread. In this case, the interceptors has to implement org.springframework.web.servlet.AsyncHandlerInterceptor interface. It extends HandlerInterceptor and provides one supplementary void method afterConcurrentHandlingStarted. This method is called instead of postHandler() and afterCompletion() every time when handler was executed correctly. It's also the moment where the request is sent to further processing. Springs tells that this type of handler can be use to clean local thread variables.

Difference between interceptors and filters

If interceptors look like servlet filters, why Spring decided to override the default Java's solution ? The major difference between these two options is the scope. Filter can be used only under servlet container. In the other side, handlers can be invoked within Spring container, so not necessarily in the web environment.

Spring's handler provides a more fine-grained control for the requests. Like we have seen it in the previous point, they can be invoked before or after the requests processing by controller, and also after rendering action's view to the user. In the case of filters, they can be applied only before returning the response to the final user.

The next difference is the simplicity of interrupting the chain execution. Interceptor can make it by simply returning false on preHandler() method. In the case of filter it's more complicated because it has to deal with request and response objects to provoke an interruption and, for example, redirects user to an error page.

What are default Spring interceptors ?

Spring uses interceptors mainly for switching operations. One of the most common used features is locale changing. Encapsulated in org.springframework.web.servlet.i18n.LocaleChangeInterceptor class, it can be made thanks to analyzing of HTTP request by one of defined locale resolvers. All locale resolvers analyze requests elements (headers, cookies) to decide which langue should be serve to user.

Another native interceptor is org.springframework.web.servlet.theme.ThemeChangeInterceptor which allows to change view's theme. It also uses resolvers (theme resolvers more precisely) to know about the theme to use. Its resolvers are also based on request analyze (cookie, session or parameter).

Custom handler interceptor in Spring

In our example we'll implement HandlerInterceptor. It won't make a complicated stuff. It will analyze every request and decide if it's a "happy winner" of a lottery in our website. To simplify the code, only the request which generate a random number that modulus operator returns 0.
public class LotteryInterceptor implements HandlerInterceptor {

	public static final String ATTR_NAME = "lottery_winner";
	private static final Logger LOGGER = LoggerFactory.getLogger(LotteryInterceptor.class);

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception {
		LOGGER.debug("[LotteryInterceptor] afterCompletion");
		
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView view) throws Exception {
		LOGGER.debug("[LotteryInterceptor] postHandle");
		
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		LOGGER.debug("[LotteryInterceptor] preHandle");
		if (request.getSession().getAttribute(ATTR_NAME) == null) {
			Random random = new Random();
			int i = random.nextInt(10);
			request.getSession().setAttribute(ATTR_NAME, i%2 == 0);
		}
		return true;
	}

}
And there are controller which uses winner's lottery attribute:
@Controller
public class TestController {
        private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class);
	@RequestMapping(value = "/test", method = RequestMethod.GET)
	public String test(HttpServletRequest request) {
		LOGGER.debug("Controller asks, are you a lottery winner ? "+request.getSession().getAttribute(LotteryInterceptor.ATTR_NAME));
    	return "test";
	}
}
If we try to access /test URL, we won't see log entries of interceptor because it isn't defined in the configuration. Suppose that we use annotation to configure the webapp. In this case, we need to add this entry into application's context file:
	<mvc:interceptors>
        <bean class="com.waitingforcode.interceptors.LotteryInterceptor" />
    </mvc:interceptors>
Remember that you can activate annotations thanks to this configuration entry: <mvc:annotation-driven /> Now we can access to /test page and check the logs. You should see there following entries:
[LotteryInterceptor] preHandle
Controller asks, are you a lottery winner ? false
[LotteryInterceptor] postHandle
[LotteryInterceptor] afterCompletion

To summarize, interceptors are a kind of servlet filters that can be applied into whole Spring's ecosystem. They can be launched before or after request, or after the view rendering. They can also be invoked in asynchronous maneer, through the implementations of AsyncHandlerInterceptor interface.


If you liked it, you should read:

📚 Newsletter Get new posts, recommended reading and other exclusive information every week. SPAM free - no 3rd party ads, only the information about waitingforcode!