发现问题,某些使用了DeferredResult的接口,每次打印两次日志,日志打印操作在拦截器中,进而发现其实是拦截器执行了两次,过滤器正常执行一次;
1.解决方案:
(1)由于异步请求使用了两个不同线程每个线程会执行一次拦截器preHandle,普通拦截器判断分发器类型,如果是异步请求进行直接放行,此时第二次重复进入拦截器则无需重复执行拦截器逻辑,注意做到幂等:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
DispatcherType dispatcherType = request.getDispatcherType();
if (dispatcherType.equals(DispatcherType.ASYNC)){
return true;
}
//其他代码....
}
(2)根据业务逻辑适当使用AsyncHandlerInterceptor拦截器的afterConcurrentHandlingStarted方法,该方法仅执行一次,是在tomcat处理请求逻辑线程中执行,并且在线程池子线程执行前执行;
//同一个线程A
AsyncTestInterceptor执行了preHandle
//这中间执行接口的同步代码
AsyncTestInterceptor执行了afterConcurrentHandlingStartedThread
过滤器执行完成
//同一个线程B
//接下来执行异步代码
AsyncTestInterceptor执行了preHandle
AsyncTestInterceptor执行了postHandle
AsyncTestInterceptor执行了afterCompletion
2.测试
添加一个过滤器:
public class CrosFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, responseServlet);
System.out.println("过滤器执行了完毕");
}
}
测试接口
@RequestMapping("/test")
public DeferredResult<String> test() {
DeferredResult<String> result = new DeferredResult<>(1000L * 3);
result.onTimeout(() -> {
result.setResult("接口超时");
});
//使用线程池执行
WfThreadPoolCallerRunsPolicyUtil.getPool().execute(() -> {
result.setResult("执行成功");
});
return result;
}
(1)普通拦截器执行顺序:
public class TestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("TestInterceptor执行了preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("TestInterceptor执行了postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("TestInterceptor执行了afterCompletion");
}
}
执行结果(preHandle执行两次):
TestInterceptor执行了preHandle
过滤器执行了完毕
TestInterceptor执行了preHandle
TestInterceptor执行了postHandle
TestInterceptor执行了afterCompletion
(2)异步拦截器:
public class AsyncTestInterceptor implements AsyncHandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("AsyncTestInterceptor执行了preHandle");
return true;
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("AsyncTestInterceptor执行了afterConcurrentHandlingStarted");
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("AsyncTestInterceptor执行了postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("AsyncTestInterceptor执行了afterCompletion");
}
}
执行结果(preHandle执行两次):
AsyncTestInterceptor执行了preHandle
AsyncTestInterceptor执行了afterConcurrentHandlingStarted
过滤器执行了完毕
AsyncTestInterceptor执行了preHandle
AsyncTestInterceptor执行了postHandle
AsyncTestInterceptor执行了afterCompletion
本文由 GY 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为:
2023/01/12 06:47