实现以下需求:生产者发送消息后,消费者延迟一定的时间收到消息消费消息,
重点看步骤3和步骤5 的代码
1 RedissonClient配置类编写,这里用的单机模式,方便测试
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonClientConfig {
@Bean
public RedissonClient getredissonclient() {
Config config = new Config();
//这里用的单机模式,方便测试
config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword("123456");
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
2 消息封装pojo创建
import lombok.Data;
import java.io.Serializable;
/**
* 任务DTO
* @param <T>
*/
@Data
public class TaskDTO<T> implements Serializable {
//任务标识,唯一,自己去控制去
private String taskName;
//发送的消息
private T taskBody;
}
import java.io.Serializable;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 通告
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Notice implements Serializable {
private Integer id;
//通告标题
private String title;
//内容
private String content;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone ="GMT+8")
private LocalDateTime addTime;
private static final long serialVersionUID = 1L;
}
3 编写生产者,往延迟队列放消息----【核心方法】
import cn.haiwang.domain.Notice;
import cn.haiwang.dto.TaskDTO;
import cn.haiwang.service.NoticeService;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
/**
* 通告(notice)表控制层 --------------Blocking -- Deque ---delay
*
* @author xxxxx
*/
@RestController
@RequestMapping("/notice")
public class NoticeController {
@Autowired
private RedissonClient redissonClient;
@Autowired
private NoticeService noticeServiceImpl;
/**
* 往延迟队列放消息,【核心方法】
*
* @param taskDTO
* @return
*/
@RequestMapping("/insert")
public String insert(@RequestBody TaskDTO<Notice> taskDTO) {
int i = noticeServiceImpl.insert(taskDTO.getTaskBody());
if (i > 0) {
//阻塞队列
RBlockingDeque<TaskDTO<Notice>> blockingDeque = redissonClient.getBlockingDeque("notice:blockQueue_delay");
//延迟队列
RDelayedQueue<TaskDTO<Notice>> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
//消费者延时30秒收到消息
delayedQueue.offer(taskDTO, 30, TimeUnit.SECONDS);
return "成功:" + taskDTO.getTaskBody().getId();
}
return "失败:" + taskDTO.getTaskBody().getId();
}
/**
* 延迟队列中的消息删除,【可选】
*
* @param taskName
* @return
*/
@RequestMapping("/cancel")
public Boolean cancel(String taskName) {
//阻塞队列
RBlockingDeque<TaskDTO<Notice>> blockingDeque = redissonClient.getBlockingDeque("notice:blockQueue_delay");
//延迟队列
RDelayedQueue<TaskDTO<Notice>> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
TaskDTO<Notice> noticeTaskDTO = delayedQueue.stream().filter(xx -> xx.getTaskName().equals(taskName)).findFirst().orElse(null);
boolean b = false;
if (noticeTaskDTO != null) {
b = delayedQueue.remove(noticeTaskDTO);
}
return b;
}
}
4 消费者消费消息--用单独的线程池处理
import io.netty.util.concurrent.DefaultThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 自定义线程池
*/
@Configuration
public class DiyThreadPool {
@Bean(value = "my_ThreadPoolExecutor_1")
@Primary
public ThreadPoolExecutor my_ThreadPoolExecutor()
{
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,
30,
600, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(50),
new DefaultThreadFactory("my_Thread_Pool_1"),
new ThreadPoolExecutor.DiscardPolicy());
return threadPoolExecutor;
}
}
5 消费者消费消息----【核心方法】,启动类上别忘记添加 @EnableAsync ,@EnableScheduling
import cn.haiwang.domain.Notice;
import cn.haiwang.dto.TaskDTO;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Service
public class Delay_Queue_Notice_Poll {
@Autowired
private RedissonClient redissonClient;
/**
* 消费消息,【核心方法】
*/
@Scheduled(cron = "0/3 * * * * ?")
@Async(value = "my_ThreadPoolExecutor_1")
public void queue_poll_data()
{
//阻塞队列
RBlockingDeque<TaskDTO<Notice>> blockingDeque = redissonClient.getBlockingDeque("notice:blockQueue_delay");
try {
//消费消息
TaskDTO<Notice> take = blockingDeque.take();
Notice notice = take.getTaskBody();
System.err.printf("正在消费数据---线程:%s---数据主键:%s---消费时间:%s \n",
Thread.currentThread().getName(),
notice.getId(),
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
System.err.println(notice);
System.err.println();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
效果如下:观察时间,延迟了30秒才收到
正在消费数据---线程:my_Thread_Pool_1-124-1---数据主键:112---消费时间:2023-11-23 23:49:50
Notice(id=112, title=从社从, content=null, isActive=88, addTime=2023-11-23T23:49:16)
使用redisson的延迟队列时,千万要注意的地方是放入消息是使用的RDelayedQueue队列,获取消息是使用RQueue队列。