Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 503
Stanislav Poslavsky Avatar asked Nov 18 '14 13:11

Stanislav Poslavsky


2 Answers

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
like image 119
Vadim Kolesnikov Avatar answered Sep 19 '22 17:09

Vadim Kolesnikov


The difference between the two invocations can be seen by examining the value of request.getDispatcherType().

like image 42
thunder Avatar answered Sep 19 '22 17:09

thunder