因为不同的业务接口所需超时时间不同,例如上传或者下载,但是大多数接口都基本可以统一一个超时时间,同时捕获异常,方便上下游子系统设置超时时间能够包住,以及业务可以根据错误码更好地判断做对应的补偿措施,前端展示失败原因
主要设计:编写BaseController,提供请求统一入口,线程池提交请求并设置超时时间,超时时间可以自定义,定义一个函数式接口TemplateInterface,请求对象需要继承BaseRequestDTO,响应对象需要继承BaseResponseDTO
BaseController
public class BaseController { private static final Logger logger = LoggerFactory.getLogger(BaseController.class); protected static final JsonMapper JSON_MAPPER = JsonMapper.nonEmptyMapper(); @Autowired @Qualifier("threadPoolTaskExecutor") private ThreadPoolTaskExecutor threadPoolTaskExecutor; @Autowired private BizSeqUtil bizSeqUtil; protected static long timeout = 7000;//默认超时时间 publicT doExecute(HttpServletRequest httpServletRequest , HttpServletResponse httpServletResponse, long timeout, E request, TemplateInterface templateInterface, T timoutResponse, T exceptionResponse) { //执行逻辑 setBizSeq(request); try { Future future = threadPoolTaskExecutor.submit(() -> { return templateInterface.apply(request); }); T baseResponseDTO = future.get(timeout, TimeUnit.MILLISECONDS); baseResponseDTO.setBizSeqNo(request.getBizSeqNo()); return baseResponseDTO; } catch (TimeoutException e) { logger.error("{}|submit request timeout exception:{}",request.getBizSeqNo(),e.getMessage()); timoutResponse.setBizSeqNo(request.getBizSeqNo()); return timoutResponse; } catch (Exception e) { logger.error("{}|submit request error:",request.getBizSeqNo(),e); exceptionResponse.setBizSeqNo(request.getBizSeqNo()); return exceptionResponse; } } //设置流水号 private void setBizSeq(E req) { if (req.getBizSeqNo() != null && req.getBizSeqNo().length() > 0) { return; } String bizSeqNo = bizSeqUtil.newBizSeq(); req.setBizSeqNo(bizSeqNo); } }
PlayerController继承BaseController
@RestController @RequestMapping("/player") @Slf4j public class PlayerController extends BaseController { @Autowired private PlayerService playerService; //@RequestCheck @RequestMapping("/list") public PlayerResponseDTO getPlayerList(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, @RequestBody PlayerRequestDTO requestDTO) { log.info("getPlayerList requestDTO:{}", JSON_MAPPER.toJson(requestDTO)); PlayerResponseDTO timeoutResponse = new PlayerResponseDTO(ErrorStatus.TIMEOUT_EXCEPTION);//超时返回 PlayerResponseDTO errorResponse = new PlayerResponseDTO(ErrorStatus.SYSTEM_ERROR);//异常返回 return doExecute(httpServletRequest, httpServletResponse, timeout, requestDTO, (request -> { PlayerResponseDTO responseDTO = playerService.getPlayerList(request); log.info("getPlayerList responseDTO:{}", JSON_MAPPER.toJson(responseDTO)); return responseDTO; }), timeoutResponse, errorResponse); } }
请求父类BaseRequestDTO和响应父类BaseResponseDTO
/** * 请求父类 */ public class BaseRequestDTO { private String bizSeqNo; //get set方法忽略 } /** * 响应父类 */ public class BaseResponseDTO { private String code = "0"; private String msg = "success"; private String bizSeqNo; private Object data; public BaseResponseDTO() { } public BaseResponseDTO(Object object) { this.code = "0"; this.msg = "success"; this.data = object; } public BaseResponseDTO(ErrorStatus errorStatus) { this.code = errorStatus.getErrCode(); this.msg = errorStatus.getErrMsg(); } public BaseResponseDTO(String code,String msg) { this.code = code; this.msg = msg; } //get set方法忽略 }
定义一个函数式接口TemplateInterface,请求对象需要继承BaseRequestDTO,相应对象需要继承BaseResponseDTO
//@FunctionalInterface public interface TemplateInterface { T apply(E r); }
创建线程池
@Bean("threadPoolTaskExecutor") public ThreadPoolTaskExecutor threadPoolExecutor(@Value("${threadPool.corePoolSize}") int corePoolSize, @Value("${threadPool.maxPoolSize}") int maxPoolSize, @Value("${threadPool.keepAliveSeconds}") int keepAliveSeconds, @Value("${threadPool.queueCapacity}") int queueCapacity, @Value("${threadPool.threadNamePrefix}") String threadNamePrefix ) { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(corePoolSize); executor.setMaxPoolSize(maxPoolSize); executor.setKeepAliveSeconds(keepAliveSeconds); executor.setQueueCapacity(queueCapacity); executor.setThreadNamePrefix(threadNamePrefix); executor.initialize(); return executor; }
接口方法添加耗时逻辑,查看效果
public PlayerResponseDTO getPlayerList(PlayerRequestDTO requestDTO) { //添加耗时逻辑,接口超时时间是7 try { Thread.sleep(10000); } catch (InterruptedException e) { throw new RuntimeException(e); } TPlayer player = new TPlayer(); BeanUtils.copyProperties(requestDTO,player); PageInfo page = requestDTO.getPage() == null ? new PageInfo() : requestDTO.getPage(); player.setPage(page); Listlist = playerDAO.selectPlayerList(player); PlayerResponseDTO responseDTO = new PlayerResponseDTO(); responseDTO.setPlayerList(list); return responseDTO; }
达到预期效果