Spring MVC InterceptorHandler用DeferredResult调用了两次


问题内容

当我使用custom HandlerInterceptor且我的控制器返回时DeferredResult
preHandle我的自定义拦截器方法在每个请求上调用两次。考虑一个玩具的例子。

我的自定义拦截器:

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 {
    }
}

我的Spring Java配置:

@Configuration
@EnableWebMvc
public class ApplicationConfiguration extends WebMvcConfigurerAdapter {

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

我的控制器:

@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;
    }
}

因此,在每次加载页面时,我都会从preHandle方法中看到两个输出。但是,如果我修改MyController以仅返回“空白”模板(而不是DeferredResult“空白”模板),则preHandle在每个页面加载中仅看到一个输出。

所以,我的问题是,为什么preHandle在使用时会被调用两次,DeferredResult并且有可能避免这种情况?


问题答案:

您需要使用org.springframework.web.servlet.AsyncHandlerInterceptor

public interface AsyncHandlerInterceptor extends HandlerInterceptor {

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

}

Spring MVC 执行顺序:

preHandle
afterConcurrentHandlingStarted
preHandle
postHandle
afterCompletion