当前位置 主页 > 服务器问题 > Linux/apache问题 >

    详解Tomcat是如何实现异步Servlet的(4)

    栏目:Linux/apache问题 时间:2019-11-08 10:56

    这部分代码在调用完 Servlet 后,会通过 request.isAsync() 来判断是否是异步请求,如果是异步请求,就设置 async = true 。如果是非异步请求就执行输出数据到客户端逻辑,同时销毁 requestresponse 。这里就完成了请求结束后不响应客户端的操作。

    为什么说Spring Boot的@EnableAsync注解不是异步Servlet

    因为之前准备写本篇文章的时候就查询过很多资料,发现很多资料写SpringBoot异步编程都是依赖于 @EnableAsync 注解,然后在 Controller 用多线程来完成业务逻辑,最后汇总结果,完成返回输出。这里拿一个掘金大佬的文章来举例《新手也能看懂的 SpringBoot 异步编程指南 》,这篇文章写得很通俗易懂,非常不错,从业务层面来说,确实是异步编程,但是有一个问题,抛开业务的并行处理来说,针对整个请求来说,并不是异步的,也就是说不能立即释放Tomcat的线程,从而不能达到异步Servlet的效果。这里我参考上文也写了一个demo,我们来验证下,为什么它不是异步的。

    @RestController
    @Slf4j
    public class TestController {
     @Autowired
     private TestService service;
    
     @GetMapping("/hello")
     public String test() {
      try {
       log.info("testAsynch Start");
       CompletableFuture<String> test1 = service.test1();
       CompletableFuture<String> test2 = service.test2();
       CompletableFuture<String> test3 = service.test3();
       CompletableFuture.allOf(test1, test2, test3);
       log.info("test1=====" + test1.get());
       log.info("test2=====" + test2.get());
       log.info("test3=====" + test3.get());
      } catch (InterruptedException e) {
       e.printStackTrace();
      } catch (ExecutionException e) {
       e.printStackTrace();
      }
      return "hello";
     }
    @Service
    public class TestService {
     @Async("asyncExecutor")
     public CompletableFuture<String> test1() throws InterruptedException {
      Thread.sleep(3000L);
      return CompletableFuture.completedFuture("test1");
     }
    
     @Async("asyncExecutor")
     public CompletableFuture<String> test2() throws InterruptedException {
      Thread.sleep(3000L);
      return CompletableFuture.completedFuture("test2");
     }
    
     @Async("asyncExecutor")
     public CompletableFuture<String> test3() throws InterruptedException {
      Thread.sleep(3000L);
      return CompletableFuture.completedFuture("test3");
     }
    }
    @SpringBootApplication
    @EnableAsync
    public class TomcatdebugApplication {
    
     public static void main(String[] args) {
      SpringApplication.run(TomcatdebugApplication.class, args);
     }
    
     @Bean(name = "asyncExecutor")
     public Executor asyncExecutor() {
      ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
      executor.setCorePoolSize(3);
      executor.setMaxPoolSize(3);
      executor.setQueueCapacity(100);
      executor.setThreadNamePrefix("AsynchThread-");
      executor.initialize();
      return executor;
     }

    这里我运行下,看看效果

    这里我请求之后,在调用容器执行业务逻辑之前打了一个断点,然后在返回之后的同样打了一个断点,在 Controller 执行完之后,请求才回到了 CoyoteAdapter 中,并且判断 request.isAsync() ,根据图中看到,是为