SpringBoot实现http请求的异步长轮询【2】— AsyncHandlerInterceptor方式

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.
     * 

* 配置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 t2() {

        log.info("controller#handler called. Thread: " +
                Thread.currentThread()
                        .getName());


        Callable callable = new Callable() {

            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 流程图

流程图.png

执行效果如下图所示:

执行结果.png

文章参考

SpringMVC-使用AsyncHandlerInterceptor拦截异步处理请求

你可能感兴趣的:(SpringBoot实现http请求的异步长轮询【2】— AsyncHandlerInterceptor方式)