在springboot中如何操作redis
修改pom文件,引入spring-boot-starter-data-redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.2.0</version>
</dependency>
spring-data-redis默认使用lettuce作为redis的客户端库。
源码分析
类图
Topic
PatternTopic
支持通配符的消息订阅模式,该模式下可以订阅一类具有相同前缀的Channel。
ChannelTopic
指定Channel进行订阅,是基于channel名称的完全匹配。
消息监听容器
public class RedisMessageListenerContainer implements InitializingBean, DisposableBean, BeanNameAware, SmartLifecycle {
}
容器实现的接口
- InitializingBean Bean初始化完成
- DisposableBean Spring容器关闭时会调用destory方法
- BeanNameAware 用于绑定bean的名称
- SmartLifecycle 基于Bean生命周期控制的接口
设置任务处理线程池
简单任务处理器(非线程池)
public class SimpleAsyncTaskExecutor {
public void execute(Runnable task, long startTimeout) {
Assert.notNull(task, "Runnable must not be null");
Runnable taskToUse = (this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);
// ConcurrencyThrottleSupport.concurrencyLimit >= 0 && startTimeout > 0
if (isThrottleActive() && startTimeout > TIMEOUT_IMMEDIATE) {
//任务限速
this.concurrencyThrottle.beforeAccess();
doExecute(new ConcurrencyThrottlingRunnable(taskToUse));
}
else {
doExecute(taskToUse);
}
}
//每次执行新任务就创建一个线程
protected void doExecute(Runnable task) {
Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
thread.start();
}
}
当消息量大时,会创建大量的线程最终导致OOM。
消息监听器
package org.springframework.data.redis.connection;
import org.springframework.lang.Nullable;
/**
* Listener of messages published in Redis.
*/
public interface MessageListener {
/**
* Callback for processing received objects through Redis.
*/
void onMessage(Message message, @Nullable byte[] pattern);
}
向容器中添加监听器
通过MessageListenerAdapter处理消息
@Configuration
public class RedisMessageListenerContainerConfig {
@Resource
private MyMessageReceiver myMessageReceiver;
@Bean
public RedisMessageListenerContainer container(){
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
// 默认基于handleMessage进行消息转发
//messageReceiver.setDefaultListenerMethod("handleMessage");
MessageListenerAdapter adapter = new MessageListenerAdapter(myMessageReceiver, "handleMessage");
container.addMessageListener(adapter, new PatternTopic("patternTopic"));
return container;
}
}
是适配器模式的一种实现,允许普通的Java对象转成消息监听器。
实现MessageListener接口
@Configuration
public class RedisMessageListenerContainerConfig {
@Resource
private MyMessageReceiver myMessageReceiver;
@Bean
public RedisMessageListenerContainer container(){
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.addMessageListener(myMessageReceiver, new PatternTopic("patternTopic"));
container.addMessageListener(myMessageReceiver, new ChannelTopic("channelTopic"));
return container;
}
}
多实例消息防重复消费
在多应用实例下,发布消息会被多个客户端进行订阅,造成重复消费问题。需要加锁进行防重复消费。
Redis原生命令
发布消息
PUBLISH channel message
时间复杂度
O(N+M),N是订阅channel的客户端数量,M是订阅pattern的客户端数量
订阅消息
基于channel订阅
SUBSCRIBE channel [channel ...]
时间复杂度
O(N),N是订阅channel的数量
基于pattern订阅
PSUBSCRIBE pattern [pattern ...]
时间复杂度
O(N),N是订阅pattern的数量