redis stream轻量级消息队列

redis 5.0 之后新推出了stream数据结构,可以实现一个轻量级的消息队列,下面通过自定义注解和springboot使用一下redis stream

1.自定义注解

java 复制代码
@Target(ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MsgStreamListener
{
    String stream();

    String group();

    String name();
}

2.定义一个listener的父类,让所有的消费者继承该类

java 复制代码
public abstract class AbstractMsgListener {
}

3.将我们的所有消费者注册到redis stream的listener中

java 复制代码
@Configuration
public class RedisConfig {

    @Autowired
    private List<AbstractMsgListener> msgListeners;

    @Autowired
    private RedisTemplate redisTemplate;

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(stringRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(stringRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    public StreamMessageListenerContainer<String, ObjectRecord<String,String>> streamMessageListenerContainer(RedisConnectionFactory connectionFactory)
    {
        StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, ObjectRecord<String,String>> options =
                StreamMessageListenerContainer.StreamMessageListenerContainerOptions.builder()
                        .pollTimeout(java.time.Duration.ofSeconds(1))
                        .targetType(String.class)
                        .build();

        //创建监听redis流的消息监听容器
        StreamMessageListenerContainer<String, ObjectRecord<String,String>> listenerContainer =
                StreamMessageListenerContainer.create(connectionFactory, options);

        //找到所有继承AbstractMsgService的类

        for (AbstractMsgListener service : msgListeners) {

            for (Method method : service.getClass().getMethods()) {

                if(method.isAnnotationPresent(MsgStreamListener.class)){

                    MsgStreamListener annotation = method.getAnnotation(MsgStreamListener.class);

                    String stream = annotation.stream();
                    String group = annotation.group();
                    String name = annotation.name();

                    StreamListener<String,ObjectRecord<String,String>> listener = (StreamListener<String, ObjectRecord<String,String>>) message -> {
                        try {
                            method.invoke(service,message);
                        }catch (Exception e){

                        }
                    };

                    //创建redis流的消息监听器
                    listenerContainer.receive(Consumer.from(group,name),
                            StreamOffset.create(stream, ReadOffset.lastConsumed()),
                            listener);

                    initializeStream(stream,name);
                }

            }
        }

        listenerContainer.start();

        return listenerContainer;
    }

    public void initializeStream(String stream,String group) {

        StreamOperations<String, Object, Object> streamOperations = redisTemplate.opsForStream();

        // 创建一个流
        try {
            streamOperations.createGroup(stream, ReadOffset.from("0"), group);
        } catch (Exception e) {
            // 流可能已存在,忽略异常
        }
    }
}

4.生产者生产消息

java 复制代码
@GetMapping("/add")
    public ResponseEntity<String> addApplication() {
        // 保存应用逻辑...

        // 发布消息到 Redis Stream
        Map<String, Object> messageData = new HashMap<>();
        messageData.put("app", "Hello World");
        RecordId applications_stream = redisTemplate.opsForStream().add("applications_stream", messageData);
        return ResponseEntity.ok("Application added successfully");
    }

5.消费者消费消息,需要继承上面定义的listener的抽象类

java 复制代码
@Component
public class Consumer extends AbstractMsgListener {

    @MsgStreamListener(group = "test1",name = "test1",stream = "applications_stream")
    public void onMessage(ObjectRecord<String, String> message)
    {
        String stream = message.getStream();
        String s = message.getId().toString();
        String value = message.getValue();

        System.out.printf("receive test1 msg stream:%s msgId:%s msgBody:%s",stream,s,value);
    }

}
相关推荐
float_六七1 小时前
IntelliJ IDEA双击Ctrl的妙用
java·ide·intellij-idea
一叶飘零_sweeeet2 小时前
从手写 Redis 分布式锁到精通 Redisson:分布式系统的并发控制终极指南
redis·分布式·redisson
大写-凌祁2 小时前
零基础入门深度学习:从理论到实战,GitHub+开源资源全指南(2025最新版)
人工智能·深度学习·开源·github
能摆一天是一天2 小时前
JAVA stream().flatMap()
java·windows
悟乙己2 小时前
Github | MoneyPrinterTurbo:自动化视频内容生成系统
自动化·github·音视频
睡觉的时候不会困3 小时前
Redis 主从复制详解:原理、配置与主从切换实战
数据库·redis·bootstrap
颜如玉3 小时前
🤲🏻🤲🏻🤲🏻临时重定向一定要能重定向🤲🏻🤲🏻🤲🏻
java·http·源码
雁于飞4 小时前
vscode中使用git、githup的基操
笔记·git·vscode·学习·elasticsearch·gitee·github
程序员的世界你不懂4 小时前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
星空寻流年4 小时前
设计模式第一章(建造者模式)
java·设计模式·建造者模式