Redis5 Stream:官方介绍:
redis.io/topics/stre…
SpringBoot整合
一、POM.xml
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
二、配置
spring:
redis:
database: 0
host: 127.0.0.1
port: 6379
password:
timeout: 2000
lettuce:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
三、使用StringRedisTemplate往Stream推送消息:
@Autowired
private StringRedisTemplate stringRedisTemplate;
public void sendExchangeMsg(TestDto testDto) {
// 组装发送消息参数
try {
ObjectRecord objectRecord = ObjectRecord.create(ContainerKey.STEAM_KEY, testDto);
RecordId recordId = this.stringRedisTemplate.opsForStream().add(objectRecord);
recordId);
}catch (Exception ex){
log.error("发送消息异常, testDto={}", testDto, ex);
}
}
四、从Stream消费消息
OrderMsgListener 使用 ApplicationRnner,在系统启动以后,初始化监听器。开始监听消费。
@Slf4j
@Component
public class RedisStreamRunner implements ApplicationRunner, DisposableBean {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Autowired
private OrderMsgListener orderMessageListener;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Value("${server.port}")
private String port;
private StreamMessageListenerContainer<String, ObjectRecord<String, TestDto>> streamMessageListenerContainer;
private StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, ObjectRecord<String, TestDto>> options() {
return StreamMessageListenerContainer.StreamMessageListenerContainerOptions.builder()
.batchSize(400)
.executor(this.threadPoolTaskExecutor)
.errorHandler(t -> log.error("redis msg listener error, e:{}", t.getMessage()))
.pollTimeout(Duration.ZERO)
.serializer(new StringRedisSerializer())
.targetType(TestDto.class)
.build();
}
@Override
public void run(ApplicationArguments args) throws Exception {
// 初始化容器
streamMessageListenerContainer = StreamMessageListenerContainer.create(this.redisConnectionFactory, options());
String streamKey = ContainerKey.STEAM_KEY;
String groupId = ContainerKey.STEAM_GROOP;
String consumerName = Inet4Address.getLocalHost().getHostName() + ":" + port;
log.info("streamKey:{},groupId:{},consumerName{}",streamKey,groupId,consumerName);
// 判断 stream 是否初始化,未初始化则进行初始化
if (!Boolean.TRUE.equals(stringRedisTemplate.hasKey(streamKey))) {
// 往 stream 发送消息,会自动创建 stream
RecordId recordId = stringRedisTemplate.opsForStream().add(streamKey, Collections.singletonMap("testKey", "testV"));
// 创建 消费者组
stringRedisTemplate.opsForStream().createGroup(streamKey, groupId);
// 删除创建
stringRedisTemplate.opsForStream().delete(streamKey, recordId);
}
// 使用监听容器监听消息,并且自动应答
streamMessageListenerContainer.receiveAutoAck(
Consumer.from(groupId, consumerName),
StreamOffset.create(streamKey, ReadOffset.lastConsumed()),
orderMessageListener);
// 启动监听
this.start();
}
/**
* 订阅容器启动
*/
public void start() {
streamMessageListenerContainer.start();
}
@Override
public void destroy() throws Exception {
this.streamMessageListenerContainer.stop();
}
OrderMsgListener 实现函数接口 StreamListener<K, V extends Record<K, ?>> ,来自定义消息的消费实现
@Slf4j
@Component
public class OrderMsgListener implements StreamListener<String, ObjectRecord<String, TesyDto>> {
@Autowired
private IOrderService iOrderService;
@Override
public void onMessage(ObjectRecord<String, TestDto> testDto) {
// 消息ID
// RecordId messageId = testDto.getId();
// 消息的key和value
TestDto testDto = testDto.getValue();
try {
iOrderService.paySuccess(testDto);
}catch (Exception e){
log.error("消息处理异常订单号:{},异常信息为{}",testDto.getOrderNo(),e.getMessage());
}
}
}