美文网首页方案系统设计与开发Java
SpringBoot实现http请求的异步长轮询【2】— Asy

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

作者: 小胖学编程 | 来源:发表于2021-11-13 11:46 被阅读0次

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

    流程图.png

    执行效果如下图所示:

    执行结果.png

    文章参考

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

    相关文章

      网友评论

        本文标题:SpringBoot实现http请求的异步长轮询【2】— Asy

        本文链接:https://www.haomeiwen.com/subject/jwsozltx.html