Redis5.0 中增加了一个数据类型Stream,它借鉴了Kafka的设计,是一个新的强大的支持多播的可持久化的消息队列。
老规矩直接上代码:
一、添加依赖
首先必须得有redis依赖,SpringBoot项目直接添加下面依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
二、Redis相关配置类
Redis配置:
@Configuration
public class RedisConfig {
@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();
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
二、消费者
//消费者
@Component
public class RedisConsumer implements StreamListener<String, MapRecord<String,String,String>> {
//队列名称
public final String streamName = "emailStream";
//组名称
public final String groupName = "emailGroup";
//消费者名称
public final String consumerName = "emailConsumer";
//注入模板
@Autowired
private StringRedisTemplate stringRedisTemplate;
//日志
private static final Logger log = LoggerFactory.getLogger(ContinueDcouponControllerNew.class);
@Override
public void onMessage(MapRecord<String, String, String> message) {
log.warn("[消费者]Stream名称{}消息内容{}",streamName,message.getValue());
//获取生产者消息
Map<String, String> msgMap = message.getValue();
//业务逻辑 略
//ps:通过 msgMap.get("key") 拿到需要参数执行业务逻辑
StreamOperations<String, String, String> streamOperations = stringRedisTemplate.opsForStream();
//消息应答
streamOperations.acknowledge( streamName,groupName,message.getId() );
}
}
三、生产者
/**
* 接口代码
*/
@RestController
public class ContinueDcouponController {
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@PostMapping("/continueDcouponNew")
public String continueDcoupon(String test) {
//业务逻辑 略
//创建Stream
StreamOperations streamOperations = redisTemplate.opsForStream();
//生产者发送消息 "emailStream"-是消费者配置的Stream队列名称
streamOperations.add("emailStream",test);
return "Success"
}
}
四、Redis-Stream配置
@Configuration
public class RedisStreamConfig {
//注入RedisConsumer
@Autowired
private RedisConsumer emailConsumer;
//注入Redis模板
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Bean
public StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, MapRecord<String,String,String>> emailListenerContainerOptions(){
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
return StreamMessageListenerContainer.StreamMessageListenerContainerOptions
.builder()
//block读取超时时间
.pollTimeout(Duration.ofSeconds(3))
//count 数量(一次只获取一条消息)
.batchSize(1)
//序列化规则
.serializer( stringRedisSerializer )
.build();
}
/**
* 开启监听器接收消息
*/
@Bean
public StreamMessageListenerContainer<String,MapRecord<String,String,String>> emailListenerContainer(RedisConnectionFactory factory,
StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, MapRecord<String,String,String>> streamMessageListenerContainerOptions){
StreamMessageListenerContainer<String,MapRecord<String,String,String>> listenerContainer = StreamMessageListenerContainer.create(factory,
streamMessageListenerContainerOptions);
//如果 流不存在 创建 stream 流
if( !redisTemplate.hasKey(emailConsumer.streamName)){
redisTemplate.opsForStream().add(emailConsumer.streamName, Collections.singletonMap("", ""));
//log.info("初始化stream {} success",emailConsumer.streamName);
System.out.println("初始化stream+"+emailConsumer.streamName+"成功!");
}
//创建消费者组
try {
redisTemplate.opsForStream().createGroup(emailConsumer.streamName,emailConsumer.groupName);
} catch (Exception e) {
//log.info("消费者组 {} 已存在",emailConsumer.groupName);
System.out.println("消费者组"+ emailConsumer.groupName+"已存在");
}
//注册消费者 消费者名称,从哪条消息开始消费,消费者类
// > 表示没消费过的消息
// $ 表示最新的消息
listenerContainer.receive(
Consumer.from(emailConsumer.groupName, emailConsumer.consumerName),
StreamOffset.create(emailConsumer.streamName, ReadOffset.lastConsumed()),
emailConsumer
);
listenerContainer.start();
return listenerContainer;
}
}