Spring Boot使用线程池处理事务任务

原文链接: https://juejin.im/post/5b3c5bfef265da0f7f447e4e

最近遇到一个小型的秒杀活动,使用 Spring Boot,没办法团队没法大规模使用 Vert.x。 好了,思路就是,将Controller里面的方法包装成一个 Runnable, 放到一个单线程的线程池里进行执行,任务成功后,将结果放入一个 Map里,前端定期轮询这个 Map。一开始简单粗暴的在某个Service里创建一个 static final 的线程池,因为有些 service 方法里面有 Transactional, 而且还使用了 Hibernate的懒加载,这种简单粗暴的写法导致 Hibernate 无法获取当前线程的session,因为这个线程是使用自己new出来的线程池的线程,不是Spring管理的。下面的写法是正常好用的。

创建一个接口

public interface AsyncService {

  /**
   * 执行异步任务
   */
  void executeAsync(String orderNo, String pwd);
}
复制代码

实现接口

里面写自己的业务逻辑

@Service
public class AsyncServiceImpl implements AsyncService {

  private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class);

  @Autowired
  private AppService appService;

  @Override
  @Async("asyncServiceExecutor")
  public void executeAsync(String orderNo, String pwd) {
    logger.info("start executeAsync");
    try {
      appService.payHandler(orderNo, pwd);
    } catch (PayException pex) {
      System.out.println(pex.getMessage());
      appService.putSeckillResult(orderNo, AppMessage.error(pex.getMessage()));
      appService.cancelOrder(orderNo);
    } catch (Exception e) {
      e.printStackTrace();
      appService.putSeckillResult(orderNo, AppMessage.error("购买失败"));
      appService.cancelOrder(orderNo);
    }
    logger.info("end executeAsync");
  }
}
复制代码

Controller

@PostMapping("/pay2")
public AppMessage pay2Controller(@RequestBody PayDTO dto) {
    String orderNo = dto.getOrderNo();
    String pwd = dto.getPwd();
    
    if (StringUtils.isEmpty(pwd) || StringUtils.isEmpty(orderNo)) {
      return RespErrorUtils.paramsError();
    }
    asyncService.executeAsync(orderNo, pwd);
    return AppMessage.success("ok");
}
复制代码

任务会在http请求来的建立,但是还没有一个执行任务的线程池。现在来创建一个受Spring管理的线程池

线程池

@Configuration
@EnableAsync
public class ExecutorConfig {

  private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);

  @Bean
  public Executor asyncServiceExecutor() {
    logger.info("start asyncServiceExecutor");
    return Executors.newSingleThreadExecutor(r -> new Thread(r, "pool-seckill"));
  }
}
复制代码

创建完之后,要在 任务上添加一个 @Async("asyncServiceExecutor") 注解,该注解的value要和 线程池的 asyncServiceExecutor() 对应上。如果你使用的 IDEA,那么可以直接 Ctrl + 任务上的注解名字,会跳到线程池这里。

你可能感兴趣的:(Spring Boot使用线程池处理事务任务)