消息隊列添加消息和消費確認以及刪除消息
/**
* 消息隊列添加消息
* @param message 隊列存儲消息
* @param queueKey 隊列
*/
public void addMessageBlockingQueue(String message,String queueKey){
Record<String,String> record = StreamRecords.objectBacked(message).withStreamKey(queueKey);
redisTemplate.opsForStream().add(record);
}
/**
* 消息隊列消費確認
* @param queueKey 消息隊列key
* @param group 分組名稱
* @param recordId 消息id
* @return 成功或者失敗
*/
public boolean messageQueueConsumptionAck(String queueKey,String group,RecordId recordId){
try {
Long result = redisTemplate.opsForStream().acknowledge(queueKey, group, recordId);
if (SUCCESS.equals(result)) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return false;
}
/**
* 消息隊列刪除消息
* @param queueKey 消息隊列key
* @param recordId 消息id
* @return
*/
public boolean messageQueueConsumptionDelField(String queueKey, RecordId recordId){
try {
Long result = redisTemplate.opsForStream().delete(queueKey, recordId);
if (SUCCESS.equals(result)) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return false;
}
創建消費者監聽處理類:
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.stream.ObjectRecord;
import org.springframework.data.redis.stream.StreamListener;
import org.springframework.stereotype.Component;
@Slf4j
@Component()
public class RedisStreamListener implements StreamListener<String, ObjectRecord<String,String>> {
@Override
public void onMessage(ObjectRecord<String, String> message) {
log.info(message.toString());
// 消息消費ack確認
redisService.messageQueueConsumptionAck("key", "group", "recordId");
// 消費完成消息直接刪除
redisService.messageQueueConsumptionDelField("key", "recordId");
}
}
創建消費者監聽類的訂閱配置:
import io.lettuce.core.RedisException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.stream.*;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.stream.StreamListener;
import org.springframework.data.redis.stream.StreamMessageListenerContainer;
import org.springframework.data.redis.stream.Subscription;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Slf4j
@RequiredArgsConstructor
@Configuration
public class Config {
private final StringRedisTemplate redisTemplate;
private final StreamListener<String, ObjectRecord<String, String>> streamListener;
@Bean
public Subscription subscription(RedisConnectionFactory factory) {
checkGroup();
// 創建Stream消息監聽容器配置
StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, ObjectRecord<String, String>> options = StreamMessageListenerContainer
.StreamMessageListenerContainerOptions
.builder()
// 設置阻塞時間
.pollTimeout(Duration.ofSeconds(1))
// 配置消息類型
.targetType(String.class)
.build();
// 創建Stream消息監聽容器
StreamMessageListenerContainer<String, ObjectRecord<String, String>> listenerContainer = StreamMessageListenerContainer.create(factory, options);
// 設置消費手動提交配置
Subscription subscription = listenerContainer.receive(
// 設置消費者分組和名稱
Consumer.from("group", "consumer-1"),
// 設置訂閱Stream的key和獲取偏移量,以及消費處理類
StreamOffset.create("key", ReadOffset.lastConsumed()),
streamListener);
// 監聽容器啓動
listenerContainer.start();
return subscription;
}
/**
* 由於訂閱需要先有stream,先做下檢查
*/
private void checkGroup() {
// 創建需要校驗的分組List
List<String> consumers = new ArrayList<>();
consumers.add("group");
StreamInfo.XInfoGroups infoGroups = null;
try {
// 獲取Stream的所有組信息
infoGroups = redisTemplate.opsForStream().groups(BaseConstant.SEND_MESSAGE_QUEUE_KEY);
} catch (RedisSystemException | RedisException | InvalidDataAccessApiUsageException ex) {
log.error("group key not exist or commend error", ex);
}
// 遍歷校驗分組是否存在
for (String consumer : consumers) {
boolean consumerExist = false;
if (Objects.nonNull(infoGroups)) {
if (infoGroups.stream().anyMatch(t -> Objects.equals(consumer, t.groupName()))) {
consumerExist = true;
}
}
// 創建不存在的分組
if (!consumerExist) {
redisTemplate.opsForStream().createGroup("key", consumer);
}
}
}
}