使用多线程提高Rest服务性能
⒈使用Runnable异步处理Rest服务
1 /** 2 *使用Runnable异步处理Rest服务 3 * @return 4 */ 5 @GetMapping("/order") 6 public Callable<String> callableOrder(){ 7 logger.info("主线程开始"); 8 System.out.println(Thread.currentThread().getId()); 9 Callable<String> result = new Callable<String>() { 10 @Override 11 public String call() throws Exception { 12 logger.info("副线程开始"); 13 Thread.sleep(1000); 14 System.out.println(Thread.currentThread().getId()); 15 logger.info("副线程返回"); 16 return "seccess"; 17 } 18 }; 19 logger.info("主线程返回"); 20 return result; 21 }
Runnable的这种形式并不能满足所有的应用场景,使用Runnable异步处理的时候,副线程必须是由主线程调起的,在实际开发的过程中,有些场景是非常复杂的。
例如,如下场景:
我们可以使用DeferredResult来解决上面复杂的场景
⒉使用DeferredResult异步处理Rest服务
1.模拟队列
1 package cn.coreqi.security.async; 2 3 import org.slf4j.Logger; 4 import org.slf4j.LoggerFactory; 5 import org.springframework.stereotype.Component; 6 7 /** 8 * 用于模拟消息队列 9 */ 10 @Component 11 public class MockQueue { 12 13 private String placeOrder; //代表下单的消息 14 15 private String completeOrder; //代表订单完成的消息 16 17 private Logger logger = LoggerFactory.getLogger(getClass()); 18 19 public String getPlaceOrder() { 20 return placeOrder; 21 } 22 23 public void setPlaceOrder(String placeOrder){ 24 new Thread(() -> { 25 logger.info("接到下单请求!" + placeOrder); 26 try { 27 Thread.sleep(1000); 28 } catch (InterruptedException e) { 29 e.printStackTrace(); 30 } 31 this.completeOrder = placeOrder; 32 logger.info("下单请求处理完成!" + placeOrder); 33 }).start(); 34 } 35 36 public String getCompleteOrder() { 37 return completeOrder; 38 } 39 40 public void setCompleteOrder(String completeOrder) { 41 this.completeOrder = completeOrder; 42 } 43 }
2.模拟结果
1 package cn.coreqi.security.async; 2 3 import org.springframework.stereotype.Component; 4 import org.springframework.web.context.request.async.DeferredResult; 5 6 import java.util.HashMap; 7 import java.util.Map; 8 9 @Component 10 public class DeferredResultHolder { 11 12 private Map<String, DeferredResult<String>> map = new HashMap<>(); //K为ID,V代表处理结果 13 14 public Map<String, DeferredResult<String>> getMap() { 15 return map; 16 } 17 18 public void setMap(Map<String, DeferredResult<String>> map) { 19 this.map = map; 20 } 21 }
3.控制器处理
1 @Autowired 2 private MockQueue mockQueue; 3 4 @Autowired 5 private DeferredResultHolder deferredResultHolder; 6 7 /** 8 * 使用DeferredResult异步处理Rest服务 9 * @return 10 * @throws InterruptedException 11 */ 12 @GetMapping("/order") 13 public DeferredResult<String> deferredResultOrder() throws InterruptedException { 14 logger.info("主线程开始"); 15 System.out.println(Thread.currentThread().getId()); 16 String orderNumber = new Random().longs(8).toString(); //生成订单号 17 mockQueue.setPlaceOrder(orderNumber); //放入到消息队列里面 18 DeferredResult<String> result = new DeferredResult<>(); 19 deferredResultHolder.getMap().put(orderNumber,result); 20 return result; 21 }
4.监听结果并返回
1 package cn.coreqi.security.async; 2 3 import org.slf4j.Logger; 4 import org.slf4j.LoggerFactory; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.context.ApplicationListener; 7 import org.springframework.context.event.ContextRefreshedEvent; 8 import org.springframework.stereotype.Component; 9 import org.springframework.util.StringUtils; 10 11 @Component 12 public class QueueListener implements ApplicationListener<ContextRefreshedEvent> { 13 @Autowired 14 private MockQueue mockQueue; //模拟的队列 15 @Autowired 16 private DeferredResultHolder deferredResultHolder; 17 18 private Logger logger = LoggerFactory.getLogger(getClass()); 19 @Override 20 public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { 21 new Thread(() -> { 22 while (true){ 23 if(StringUtils.hasText(mockQueue.getCompleteOrder())){ 24 String oderNumber = mockQueue.getCompleteOrder(); //拿到订单号 25 logger.info("返回订单处理结果:" + oderNumber); 26 deferredResultHolder.getMap().get(oderNumber).setResult("place order success"); 27 mockQueue.setCompleteOrder(null); 28 }else{ 29 try { 30 Thread.sleep(100); 31 } catch (InterruptedException e) { 32 e.printStackTrace(); 33 } 34 } 35 } 36 }).start(); 37 } 38 }
⒊异步相关配置
1 package cn.coreqi.security.config; 2 3 import org.springframework.context.annotation.Configuration; 4 import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer; 5 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 6 7 @Configuration 8 public class WebConfig implements WebMvcConfigurer { 9 10 /** 11 * 配置异步支持 12 * @param configurer 13 */ 14 @Override 15 public void configureAsyncSupport(AsyncSupportConfigurer configurer) { 16 //configurer.registerCallableInterceptors(); //设置异步的拦截器 17 //configurer.registerDeferredResultInterceptors(); //设置异步的拦截器 18 //configurer.setDefaultTimeout(20000); //设置超时时间 19 //configurer.setTaskExecutor(); //默认情况下Spring用自己简单的异步线程池来处理,不会重用池里面的线程, 20 //而是每次调用时都会开启新的线程,可以自己设置一些可重用的线程池来替换 21 //Spring默认的简单异步线程池。 22 } 23 }