SpringBoot下实现http请求的长轮询—AsyncContext【推拉结合的配置更新】 在这篇文章中,可以使用AsyncContext实现异步长轮询。其实SpringMVC的拦截机制也可以实现这种操作。
1. 场景
客户端调用服务端接口,服务端这个接口比较耗时。为了优化服务端的性能。
服务端收到servlet请求后,释放掉servlet占用的线程资源。开启一个异步线程去处理耗时的操作。当耗时操作处理完成后,将结果返回给客户端。
注意:在此期间,客户端和服务端的http链接并不会断开,客户端依旧苦苦等待响应数据;
2. 实现
可以使用接口AsyncHandlerInterceptor实现来拦截涉及异步处理的请求,而不是使用HandlerInterceptor。
HandlerInterceptorAdapter适配器,适配了AsyncHandlerInterceptor和HandlerInterceptor,推荐使用这个来实现。
void afterConcurrentHandlingStarted(HttpServletRequest request,
HttpServletResponse response,
Object handler)
throws Exception
2.1 代码实现
2.1.1 实现异步线程池
上文说到,释放Servlet线程,交由指定的线程池去处理,那么如何去定义指定的线程池?
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Autowired
private MyAsyncHandlerInterceptor myAsyncHandlerInterceptor;
//配置拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//测试异步拦截器
registry.addInterceptor(myAsyncHandlerInterceptor).addPathPatterns("/**");
}
/**
* An Executor is required to handle java.util.concurrent.Callable return values.
* Please, configure a TaskExecutor in the MVC config under "async support".
* The SimpleAsyncTaskExecutor currently in use is not suitable under load.
* <p>
* 配置SpringMVC的支持
*/
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
//核心线程数
threadPoolTaskExecutor.setCorePoolSize(5);
threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
//最大线程数
threadPoolTaskExecutor.setMaxPoolSize(5);
//配置队列大小
threadPoolTaskExecutor.setQueueCapacity(50);
//配置线程池前缀
threadPoolTaskExecutor.setThreadNamePrefix("async-service-");
threadPoolTaskExecutor.initialize();
configurer.setTaskExecutor(threadPoolTaskExecutor);
}
}
2.1.2 实现拦截器
@Slf4j
@Service
public class MyAsyncHandlerInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
log.info("interceptor#preHandle called.");
return true;
}
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
log.info("interceptor#postHandle called. ");
}
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) throws Exception {
log.info("interceptor#afterCompletion called.");
}
/**
* 这个方法执行后,会执行Controller方法返回的callable方法。
* 这个方法的目的时,当servlet线程被释放后,执行清除例如ThreadLocal、MDC等资源的操作。
*/
public void afterConcurrentHandlingStarted(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
log.info("interceptor#afterConcurrentHandlingStarted. ");
}
}
2.1.3 Controller代码
注意:方法返回的是Callable。
@Slf4j
@RestController
public class FirstController {
@RequestMapping(value = "/t2")
public Callable<String> t2() {
log.info("controller#handler called. Thread: " +
Thread.currentThread()
.getName());
Callable<String> callable = new Callable<String>() {
public String call() throws Exception {
log.info("controller-callable#async task started. Thread: " +
Thread.currentThread()
.getName());
Thread.sleep(300);
log.info("controller-callable#async task finished");
return "async result";
}
};
log.info("controller#handler finished");
return callable;
}
}
3. 流程
3.1 流程图
执行效果如下图所示: