一、背景
Stream类型是 redis5之后新增的类型,在这篇文章中,我们实现使用Spring boot data redis来消费Redis Stream中的数据。实现独立消费和消费组消费。
二、整合步骤
1、引入jar包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
</dependencies>
主要是上方的这个包,其他的不相关的包此处省略导入。
2、配置RedisTemplate依赖
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// 这个地方不可使用 json 序列化,如果使用的是ObjectRecord传输对象时,可能会有问题,会出现一个 java.lang.IllegalArgumentException: Value must not be null! 错误
redisTemplate.setHashValueSerializer(RedisSerializer.string());
return redisTemplate;
}
}
注意:
此处需要注意 setHashValueSerializer 的序列化的方式,具体注意事项后期再说。
3、准备一个实体对象
这个实体对象是需要发送到Stream中的对象。
@Getter
@Setter
@ToString
public class Book {
private String title;
private String author;
public static Book create() {
com.github.javafaker.Book fakerBook = Faker.instance().book();
Book book = new Book();
book.setTitle(fakerBook.title());
book.setAuthor(fakerBook.author());
return book;
}
}
每次调用create方法时,会自动产生一个Book的对象,对象模拟数据是使用javafaker来模拟生成的。
4、编写一个常量类,配置Stream的名称
/**
* 常量
*
*/
public class Cosntants {
public static final String STREAM_KEY_001 = "stream-001";
}
5、编写一个生产者,向Stream中生产数据
1、编写一个生产者,向Stream中产生ObjectRecord类型的数据
/**
* 消息生产者
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class StreamProducer {
private final RedisTemplate<String, Object> redisTemplate;
public void sendRecord(String streamKey) {
Book book = Book.create();
log.info("产生一本书的信息:[{}]", book);
ObjectRecord<String, Book> record = StreamRecords.newRecord()
.in(streamKey)
.ofObject(book)
.withId(RecordId.autoGenerate());
RecordId recordId = redisTemplate.opsForStream()
.add(record);
log.info("返回的record-id:[{}]", recordId);
}
}
2、每隔5s就生产一个数据到Stream中
/**
* 周期性的向流中产生消息
*/
@Component
@AllArgsConstructor
public class CycleGeneratorStreamMessageRunner implements ApplicationRunner {
private final StreamProducer streamProducer;
@Override
public void run(ApplicationArguments args) {
Executors.newSingleThreadScheduledExecutor()
.scheduleAtFixedRate(() -> streamProducer.sendRecord(STREAM_KEY_001),
0, 5, TimeUnit.SECONDS);
}
}
三、独立消费
独立消费指的是脱离消费组的直接消费Stream中的消息,是使用 xread方法读取流中的数据