SpringBoot 中使用Redis Stream 实现消息监听优化

在之前的文章SpringBoot 中使用Redis Stream 实现消息监听中的demo代码写的比较乱,而且也有部分问题,随着最近有些小伙伴的交流我整理了一下代码,后续还会继续优化,感兴趣的可以在码云里拉取后实验和修改——码云地址hlove/redismq

整理部分

整理后的代码我将redis的stream名称配置和组名通过配置文件的方式进行配置,application.yml文件如下:

spring:
  redis:
    host: 127.0.0.1
    password: yourpassword
    port: 6379
#stream 相关配置
redis-stream:
  #stream 名称数组
  names: mystream1,mystream2
  #stream 群组名称
  groups: group1

stream名称和组名都可以设置为数组的形式,监听多个stream或组,接收消息的 ListenerMessage 类整理如下:

@Slf4j
public class ListenerMessage implements StreamListener<String, MapRecord<String, String, String>> {

    RedisUtil redisUtil;

    public ListenerMessage(RedisUtil redisUtil){
        this.redisUtil = redisUtil;
    }

    @Override
    public void onMessage(MapRecord<String, String, String> entries) {
        try{
            log.info("接受到来自redis的消息");
            System.out.println("message id "+entries.getId().getValue());
            System.out.println("stream "+entries.getStream());
            System.out.println("body "+entries.getValue());
            redisUtil.delField(entries.getStream(),entries.getId().getValue());
        }catch (Exception e){
            log.error("error message:{}",e.getMessage());
        }
    }

}

onMessage方法用于接收消息,最后调用的delField方法用于删除读取后的消息,这里可以根据业务需求来决定你需不需要删除。
接下来就是需要将监听启动注入到spring中,对应的类为——RedisStreamConfig,代码如下:

@Slf4j
@Configuration
public class RedisStreamConfig {

    private final ListenerMessage streamListener;
    private final RedisUtil redisUtil;

    @Value("${redis-stream.names}")
    private String[]redisStreamNames;
    @Value("${redis-stream.groups}")
    private String[]groups;

    @Autowired
    public RedisStreamConfig(RedisUtil redisUtil){
        this.redisUtil = redisUtil;
        this.streamListener = new ListenerMessage(redisUtil);
    }

    @Bean
    public List<Subscription> subscription(RedisConnectionFactory factory){
        List<Subscription> resultList = new ArrayList<>();
        var options = StreamMessageListenerContainer
                .StreamMessageListenerContainerOptions
                .builder()
                .pollTimeout(Duration.ofSeconds(1))
                .build();
        for (String redisStreamName : redisStreamNames) {
            initStream(redisStreamName,groups[0]);
            var listenerContainer = StreamMessageListenerContainer.create(factory,options);
            Subscription subscription = listenerContainer.receiveAutoAck(Consumer.from(groups[0], this.getClass().getName()),
                    StreamOffset.create(redisStreamName, ReadOffset.lastConsumed()), streamListener);
            resultList.add(subscription);
            listenerContainer.start();
        }
        return resultList;
    }


    private void initStream(String key, String group){
        boolean hasKey = redisUtil.hasKey(key);
        if(!hasKey){
            Map<String,Object> map = new HashMap<>();
            map.put("field","value");
            RecordId recordId = redisUtil.addStream(key, map);
            redisUtil.addGroup(key,group);
            //将初始化的值删除掉
            redisUtil.delField(key,recordId.getValue());
            log.info("stream:{}-group:{} initialize success",key,group);
        }
    }
}

首先将配置中的stream和group获取到,然后在注入的方法中循环启动监听,注意里面的 this.getClass().getName() ,这个只是我使用这个类的名称作为消费者,大家可以根据实际需求修改这里。
下面的方法——initStream方法用于初始化stream,这也是之前代码中存在的一个问题,有的小伙伴在没有通过命令建立stream时启动会报错,就是因为没有对应的stream,这次通过这个方法可以避免这样的问题。

代码运行

如果你拉取了我的这个demo的话启动也是很简单的,只需要修改application.yml中的相关配置后就可以直接启动,注意的是你的redis版本应该大于5,然后直接启动就可以了。通过下面的测试接口进行测试发送消息

@GetMapping("/sendTest/{streamName}")
    public String addStream(@PathVariable String streamName){
        Map<String,Object> message = new HashMap<>();
        message.put("test","hello redismq");
        message.put("send time", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        return redisUtil.addStream(streamName, message).getValue();
    }

采用restful请求格式例如:

http://localhost:8080/test/sendTest/mystream1

观察控制台打印会发现有对应的消息打印出来说明运行成功!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@胡海龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值