最近做一个小小小小商城,有一个需求就是需要在订单24小时内未付款将订单取消的需求,本来想着弄个定时任务随便搞一搞就完事了,但是本着以用户体验至上的原则,还是好好做吧。
在Java的并发包里有一个java.util.concurrent.DelayQueue
,要用这个队列必须要有一个类实现java.util.concurrent.Delayed
接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @Data public class OrderCancelDelayedImpl implements Delayed {
public OrderCancelDelayedImpl(Long id, LocalDate executeTime) { this.id = id; this.executeTime = executeTime; }
private Long id; private LocalDateTime executeTime;
@Override public long getDelay(TimeUnit unit) { return executeTime.isBefore(LocalDateTime.now()) ? -1 : 1; }
@Override public int compareTo(Delayed o) { if (this == o) { return 0; } if (o instanceof OrderCancelDelayedImpl) { return this.executeTime.compareTo(((OrderCancelDelayedImpl) o).getExecuteTime()); } else { throw new RuntimeException("this is a error message"); } } }
|
主要实现两个方法:
getDelay
:官方给的解释Returns the remaining delay associated with this object, in the given time unit.
,简单来说就是用来判断什么时候出列。返回值大于0不出列,反之出列。
compareTo
:这个没啥说的就是做个比较看看是不是放重了。
在这个类中有两个属性:
id
:主要记录要取消那个订单。
executeTime
:执行取消订单的时间,前期主要作用是判断执不执行。
其中的属性可以根据自己的需求来添加。
然后是创建一个一个队列
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@Configuration public class OrderConfig {
@Bean public DelayQueue<OrderCancelDelayedImpl> delayQueue() { return new DelayQueue<>(); } }
|
然后是在什么时候将DelayedImpl
放入队列,我的需求是确认订单后24小时未付款取消订单,需要在订单创建完成之后将订单信息放入队列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Slf4j @Service("orderService") public class OrderServiceImpl{ public void create(Order order) { LocalDateTime now = LocalDateTime.now(); order.setCreateTime(now); orderDao.insert(order); delayQueue.put(new OrderCancelDelayedImpl(order.getId(), now)); } }
|
然后我们需要启动一个线程来取消超过24小时未付款的订单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
@Slf4j public class CancelOrderThread extends Thread {
@Resource(name = "orderService") private OrderService orderService;
@Resource(name = "delayQueue") private DelayQueue<OrderCancelDelayedImpl> delayQueue;
@Override public void run() { OrderCancelDelayedImpl delayed; while (true) { try {
delayed = delayQueue.take(); orderService.cancel(new Order(delayed.getOrderId())); log.info("------ id为" + delayed.getOrderId() + "订单已被取消 ------");
} catch (InterruptedException e) { if (delayed != null) { log.error("------ id为" + delayed.getOrderId() + "订单取消失败 ------", e); } } } } }
|
然后再OrderConfig
注册CancelOrderThread
1 2 3 4
| @Bean public CancelOrderThread cancelOrderThread() { return new CancelOrderThread(); }
|
最后则是在启动服务器的时候启动该线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
@Slf4j @Component public class ServerStartedListenerCancelOrderThread implements ApplicationListener<ContextRefreshedEvent> {
@Resource(name = "cancelOrderThread") private CancelOrderThread cancelOrderThread;
@Override public void onApplicationEvent(ContextRefreshedEvent event) { if (event.getApplicationContext().getParent() == null) { cancelOrderThread.start(); log.info("------ 取消订单线程开始工作 ------"); } } }
|