在做项目业务的时候一直都有用到redis。在一些小项目背景上,引用大型的mq可能不是特别适用,并且很多mq对延时队列的支持大多不太友好。比如rabbitmq是最能自定义时间的但是需要安装插件,rocketmq的自定义时间需要花钱买阿里云的,kafka则没有对应的实现。因此本框架借鉴了rabbitmq和springboot整合的思路,rocketmq和springboot整合的思路,参考了redission的延时队列。开发了一套支持各种队列消息的功能。
发送普通消息
发送延时消息
发送定时执行的消息
发送顺序消息
定时给redis发送心跳注册自身,项目启动和新的客户端加入时会对所有客户端执行重平衡。
topic等共同于rocketmq的topic
virtualQueue虚拟队列等同于rocketmq的队列,默认1个(多个队列在redis集群时有用)
queueMaxSize队列最大长度由于redis是内存数据库,因此对队列的数量进行了限制(消息的堆积能力不足其他mq)
tag等同于rocketmq的tag
group用来对消息集群分组
不同的group的队列消息,客户端都会进行隔离。
相同的服务多个实例使用相同group,每个服务的group都不能相同
<dependency>
<groupId>io.github.zhaohaohgroupId>
<artifactId>redismq-spring-boot-autoconfigureartifactId>
<version>Latest Versionversion>
dependency>
/**
* @Author: hzh
* @Date: 2022/12/26 17:54
* 生产消息的例子
*/
@RestController
@RequestMapping("producer")
public class ProducerController {
@Autowired
private RedisMQTemplate redisMQTemplate;
/**
* 发送延迟消息
*/
@PostMapping("sendDelayMessage")
public void sendDelayMessage() {
redisMQTemplate.sendDelayMessage("延时消息消费", "delaytest1", Duration.ofSeconds(60));
}
/**
* 发送普通消息
*/
@PostMapping("sendMessage")
public void sendMessage() {
redisMQTemplate.sendMessage("普通消息消费", "test1");
}
/**
* 发送顺序消息
*/
@PostMapping("sendOrderMessage")
public void sendOrderMessage() {
redisMQTemplate.sendMessage("顺序消息消费", "order");
}
/**
* 发送定时消费消息 带tag
*/
@PostMapping("sendTimingMessage")
public void sendTimingMessage() {
LocalDateTime time = LocalDateTime.of(2022, 12, 26, 14, 20, 30);
long l = time.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
redisMQTemplate.sendTimingMessage("定时消息消费", "time", "bussiness1", l);
}
/**
* 发送定时消费消息 带tag
*/
@PostMapping("sendMultiTagMessage")
public void sendMultiTagMessage() {
redisMQTemplate.sendMessage("多个标签同一topic消息消费1", "MultiTag", "bussiness1");
redisMQTemplate.sendMessage("多个标签同一topic消息消费2", "MultiTag", "bussiness2");
redisMQTemplate.sendMessage("多个标签同一topic消息消费1", "MultiTag", "bussiness1");
redisMQTemplate.sendMessage("多个标签同一topic消息消费2", "MultiTag", "bussiness2");
redisMQTemplate.sendMessage("多个标签同一topic消息消费1", "MultiTag", "bussiness1");
redisMQTemplate.sendMessage("多个标签同一topic消息消费2", "MultiTag", "bussiness2");
redisMQTemplate.sendMessage("多个标签同一topic消息消费1", "MultiTag", "bussiness1");
redisMQTemplate.sendMessage("多个标签同一topic消息消费2", "MultiTag", "bussiness2");
}
}
/**
* @Author: hzh
* @Date: 2022/12/26 17:54
* 消费者简单案例
*/
@Component
public class SamplesConsumer {
/**
* delaytest1消费延时队列
*/
@RedisListener(topic = "delaytest1", delay = true)
public void delaytest1(String test) {
System.out.println(test);
}
/**
* 普通消息消费
*/
@RedisListener(topic = "test1")
public void test1(String test) {
System.out.println(test);
}
/**
* 顺序消息消费 虚拟队列,消费者线程都设置为1即可保证顺序
*/
@RedisListener(topic = "order", virtual = 1, concurrency = 1, maxConcurrency = 1)
public void order(Message message) {
System.out.println(message);
}
@RedisListener(topic = "time",tag = "bussiness1",delay = true)
public void time(Message message) {
System.out.println(message);
}
/**
* 多标签同topic消费,会由同一个线程池进行消费
*
* @param message 消息
*/
@RedisListener(topic = "MultiTag",tag = "bussiness1")
public void multiTag1(Message message) {
//模拟业务消费
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name+message);
}
@RedisListener(topic = "MultiTag",tag = "bussiness2")
public void multiTag2(Message message) {
//模拟业务消费
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name+message);
}
}
由于内存队列的特性,无法堆积消息(消息累积到一定数量会拒绝)。因此框架提供了发送消息的生产者前后回调和消费者前后回调。
默认消费失败加入redis的死信队列
默认生产发消息失败打印失败日志
可自定义实现对消息持久化mysql等第三方存储库
@Configuration
public class RedisMQInterceptorConfiguration {
@Bean
public ConsumeInterceptor redisDeadQueueHandleInterceptor() {
return new 自定义ConsumeInterceptor实现类();
}
@Bean
public ProducerInterceptor producerInterceptor() {
return new 自定义ProducerInterceptor实现类();
}
}
喜欢的点个赞
github
gitee
缺点:目前只提供了spring-redis的api对框架的操作进行实现。