定时消息

319 阅读1分钟

应用场景

根据数据库消息表存入的消息推送时间,定时执行消息推送

实现方案

1. 定时任务 使用定时任务定期扫描数据库的消息数据,比较每个推送时间小于当前时间并没有被执行推送的消息,得到消息列表,执行推送任务。

2. 定时器 使用定时器来处理消息推送。每次向数据库中添加一条消息数据时,创建一个对应的定时器,定时器的触发时间为消息的推送时间,当定时器触发时,执行推送操作.并在系统重启时从数据库查询未被推送的消息,重新生成定时器。

3. 消息队列 通过MQ消息队列中间件实现定时消息的推送,相对更可靠和稳定

示例

定时器实现举例

@Entity
@Data
public class Message {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String content;

    private LocalDateTime pushTime;

    private boolean pushed;
}

@Service
public class MessageService {
    @Autowired
    private MessageRepository messageRepository;

    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

    private Map<Long, ScheduledFuture<?>> scheduledFutures = new HashMap<>();

    public void addMessage(Message message) {
        message.setPushed(false);
        messageRepository.save(message);

        LocalDateTime pushTime = message.getPushTime();
        long delay = Duration.between(LocalDateTime.now(), pushTime).toMillis();

        ScheduledFuture<?> scheduledFuture = scheduledExecutorService.schedule(() -> {
            pushMessage(message);
        }, delay, TimeUnit.MILLISECONDS);

        scheduledFutures.put(message.getId(), scheduledFuture);
    }

    public void deleteMessage(Long messageId) {
        Message message = messageRepository.findById(messageId).orElse(null);
        if (message == null) {
            return;
        }

        ScheduledFuture<?> scheduledFuture = scheduledFutures.get(messageId);
        if (scheduledFuture != null) {
            scheduledFuture.cancel(false);
            scheduledFutures.remove(messageId);
        }

        messageRepository.delete(message);
    }

    @PostConstruct
    public void initScheduledFutures() {
        List<Message> messages = messageRepository.findByPushTimeAfter(LocalDateTime.now());
        for (Message message : messages) {
            addMessage(message);
        }
    }

    @PreDestroy
    public void stopScheduledFutures() {
        scheduledExecutorService.shutdown();
    }

    private void pushMessage(Message message) {
        // 实现消息推送逻辑,例如调用接口推送消息给用户
        message.setPushed(true);
        messageRepository.save(message);
    }
}

消息队列实现举例

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
@Service
public class MessageService {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void addMessage(Message message) {
        message.setPushed(false);

        rabbitTemplate.convertAndSend("message-exchange", "message-routing-key", message, message1 -> {
            message1.getMessageProperties().setExpiration(String.valueOf(Duration.between(LocalDateTime.now(), message.getPushTime()).toMillis()));
            return message1;
        });
    }

    private void pushMessage(Message message) {
        // 实现消息推送逻辑,例如调用接口推送消息给用户
        message.setPushed(true);
        // 更新消息状态
    }
}
@Component
public class MessageConsumer {
    @Autowired
    private MessageService messageService;

    @RabbitListener(queues = "message-queue")
    public void handleMessage(Message message) {
        messageService.pushMessage(message);
    }
}
**```**