使用多线程提高REST服务器性能
异步处理REST服务
1、使用Runnable异步处理Rest服务
释放主线程,启用副线程进行处理,副线程处理完成后直接返回请求
主要代码
import java.util.concurrent.Callable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * * @author hzc * */ @RestController public class AsyncController { private Logger logger = LoggerFactory.getLogger(AsyncController.class); @RequestMapping("/order") public Callable<String> order() throws InterruptedException { logger.info("主线程开始"); Callable<String> result = new Callable<String>() { @Override public String call() throws Exception { logger.info("副线程开始"); Thread.sleep(1000); logger.info("副线程结束"); return "success"; } }; logger.info("主线程返回"); return result; } }
2、使用DeferredResult异步处理Rest服务
释放主线程,启用副线程1进行前处理,副线程2进行后处理,副线程2处理完后返回请求
模拟业务场景
主线程调用副线程1进行业务处理,将任务放于消息队列,副线程2监听消息队列,并处理队列的任务,在使用DeferredResult获取队列返回的结果,返回给前端
Controller类
package com.maple.security.web.async; import org.apache.commons.lang.RandomStringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; /** * * @author hzc * */ @RestController public class AsyncController { private Logger logger = LoggerFactory.getLogger(AsyncController.class); @Autowired private MockQueue mockQueue; @Autowired private DeferredResultHolder deferredResultHolder; @RequestMapping("/order") public DeferredResult<String> order() throws InterruptedException { logger.info("主线程开始"); String orderNumber = RandomStringUtils.randomNumeric(8); mockQueue.setPlaceOrder(orderNumber); DeferredResult<String> result = new DeferredResult<>(); deferredResultHolder.getMap().put(orderNumber, result); logger.info("主线程返回"); return result; } }
模拟消息队列类
package com.maple.security.web.async; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * * @author hzc * */ @Component public class MockQueue { private Logger logger = LoggerFactory.getLogger(MockQueue.class); // 生成下单 private String placeOrder; // 完成下单 private String completeOrder; public String getPlaceOrder() { return placeOrder; } public void setPlaceOrder(String placeOrder) { new Thread(() -> { logger.info("接到下单请求"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } this.completeOrder = placeOrder; logger.info("下单请求处理完毕," + placeOrder); }).start(); } public String getCompleteOrder() { return completeOrder; } public void setCompleteOrder(String completeOrder) { this.completeOrder = completeOrder; } }
监听消息队列并处理类
package com.maple.security.web.async; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; @Component public class QueueListener implements ApplicationListener<ContextRefreshedEvent> { private Logger logger = LoggerFactory.getLogger(QueueListener.class); @Autowired private MockQueue mockQueue; @Autowired private DeferredResultHolder deferredResultHolder; @Override public void onApplicationEvent(ContextRefreshedEvent event) { new Thread(() -> { while (true) { if (StringUtils.isNotBlank(mockQueue.getCompleteOrder())) { String orderNumber = mockQueue.getCompleteOrder(); logger.info("返回订单处理结果:" + orderNumber); deferredResultHolder.getMap().get(orderNumber).setResult("place order success"); mockQueue.setCompleteOrder(null); } else { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } }
异步处理结果类
/** * */ package com.maple.security.web.async; import java.util.HashMap; import java.util.Map; import org.springframework.stereotype.Component; import org.springframework.web.context.request.async.DeferredResult; /** * @author hzc * */ @Component public class DeferredResultHolder { private Map<String, DeferredResult<String>> map = new HashMap<String, DeferredResult<String>>(); public Map<String, DeferredResult<String>> getMap() { return map; } public void setMap(Map<String, DeferredResult<String>> map) { this.map = map; } }
3、异步处理配置