Stanislav Poslavsky Stanislav Poslavsky - 1 month ago 26
Java Question

Spring MVC InterceptorHandler called twice with DeferredResult

When I am using custom

HandlerInterceptor
and my controller returns
DeferredResult
, the
preHandle
method of my custom interceptor called twice on each request. Consider a toy example.

My custom interceptor:

public class MyInterceptor implements HandlerInterceptor {
static int i = 0;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(i++);
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}


My Spring Java configuration:

@Configuration
@EnableWebMvc
public class ApplicationConfiguration extends WebMvcConfigurerAdapter {

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
}


My Controller:

@Controller
public class MyController {

@RequestMapping(value = "/test", method = RequestMethod.GET)
public DeferredResult<String> test() {
DeferredResult<String> df = new DeferredResult<String>();
df.setResult("blank");
return df;
}
}


So, on each page load I see two outputs from
preHandle
method. However, if I modify
MyController
in order to return just "blank" template (instead of
DeferredResult
with "blank" template), I see just one output from
preHandle
on each page load.

So, my question is why
preHandle
called twice when I use
DeferredResult
and is it possible to avoid this?

Answer

You need to use org.springframework.web.servlet.AsyncHandlerInterceptor:

public interface AsyncHandlerInterceptor extends HandlerInterceptor {

    void afterConcurrentHandlingStarted(
            HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;

}

Spring MVC execute sequence:

preHandle
afterConcurrentHandlingStarted
preHandle
postHandle
afterCompletion