springboot2默认已经使用了lettuce-core,没有使用jedis和Redisson,springboot1使用的是jedis。
我使用的springboot版本是2.6.14。(对应的lettuce版本为6.1.10.RELEASE,对应jedis版本为3.7.1)
<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>
连接到Redis
您可以像注入任何其他Spring Bean一样,注入一个自动配置的RedisConnectionFactory、StringRedisTemplate或普通RedistTemplate实例。下面的清单显示了这样一个bean的示例:
单机模式的配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
spring.redis.username=user
spring.redis.password=secret
spring:
redis:
host: "localhost"
port: 6379
database: 0
username: "user"
password: "secret"
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
//解决序列化丢失类型信息
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
//反序列化
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
//使用Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是JDK序列化)
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(RedisSerializer.string());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
/**
* @author
* 配置redis序列化json
*/
@Configuration
public class RedisConfiguration {
@Bean
/**
* 若有相同类型的Bean时,优先使用此注解标注的Bean
*/
@Primary
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 为了开发方便,一般直接使用<String, Object>
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// 配置具体的序列化方式
// JSON解析任意对象
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会抛出异常
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
// 设置日期格式
om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
jackson2JsonRedisSerializer.setObjectMapper(om);
// String的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化
template.setHashKeySerializer(stringRedisSerializer);
// value的序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
// 设置所有配置
template.afterPropertiesSet();
return template;
}
}
哨兵(sentinel)模式的配置
spring:
redis:
sentinel:
master: mymaster
nodes:
- 127.0.0.1:27001
- 127.0.0.1:27001
- 127.0.0.1:27001
spring:
redis:
sentinel:
master: mymaster
nodes: 192.168.211.158:6382,192.168.211.158:6383,192.168.211.158:6384
配置类中添加以下配置
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}
这里的ReadFrom是配置Redis的读取策略,是一个枚举类,有以下选择
- MASTER:从主节点读取
- MASTER_PREFERRED:优先从master节点读取,master不可用才读取slave节点
- REPLICA:从slave节点读取
- REPLICA_PREFERRED:优先从slave节点读取,所有slave不可用才读取master(推荐)
至此,配置已经完成,再使用redisTemplate时读会从slave节点,写会从master节点
@Configuration
public class RedisConfiguration {
/**
*
* 配置redis序列化json
* @param redisConnectionFactory
* @return
*/
@Bean
@Primary //若有相同类型的Bean时,优先使用此注解标注的Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 为了开发方便,一般直接使用<String, Object>
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// 配置具体的序列化方式
// JSON解析任意对象
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
// 设置日期格式
om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
jackson2JsonRedisSerializer.setObjectMapper(om);
// String的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采用String的序列化
template.setKeySerializer(stringRedisSerializer);
//value的序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
//hash的key也采用String的序列化
template.setHashKeySerializer(stringRedisSerializer);
//hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
//设置所有配置
// 设置支持事物
redisTemplate.setEnableTransactionSupport(true);
template.afterPropertiesSet();
return template;
}
/**
* 配置读写分离
* @param redisProperties
* @return
*/
@Bean
public RedisConnectionFactory lettuceConnectionFactory(RedisProperties redisProperties) {
// 配置哨兵节点以及主节点
RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration(
redisProperties.getSentinel().getMaster(), new HashSet<>(redisProperties.getSentinel().getNodes())
);
// 配置读写分离
LettucePoolingClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()
// 读写分离,这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择
// MASTER 仅读取主节点
// MASTER_PREFERRED 优先读取主节点,如果主节点不可用,则读取从节点
// REPLICA_PREFERRED 优先读取从节点,如果从节点不可用,则读取主节点
// REPLICA 仅读取从节点
// NEAREST 从最近节点读取
// ANY 从任意一个从节点读取
.readFrom(ReadFrom.REPLICA_PREFERRED)
.build();
return new LettuceConnectionFactory(redisSentinelConfiguration, lettuceClientConfiguration);
}
}
集群(cluster)模式的配置
spring:
redis:
cluster:
# 集群节点
nodes: 192.168.211.158:6382,192.168.211.158:6383,192.168.211.158:6384,192.168.211.158:6385,192.168.211.158:6386,192.168.211.158:6387
# 最大重定向次数
max-redirects: 5
# 密码
password: myredis
lettuce:
pool:
min-idle: 0
max-active: 8
max-wait: -1
max-idle: 8
enabled: true
spring:
redis:
cluster:
nodes: # 指定分片集群中的每个节点信息
- 127.0.0.1:7:7001
- 127.0.0.1:7:7002
- 127.0.0.1:7:7003
- 127.0.0.1:7:8001
- 127.0.0.1:7:8002
- 127.0.0.1:7:8003
spring:
redis:
# redis哨兵配置
sentinel:
# 主节点名称
master: mymaster
nodes:
- 192.168.159.100:26380
- 192.168.159.100:26381
- 192.168.159.100:26382
# # 集群的部署方式
# cluster:
# nodes:
# - 192.168.158.100:6380
# - 192.168.158.100:6381
# - 192.168.158.100:6382
# # #最大重定向次数(由于集群中数据存储在多个节点,所以在访问数据时需要通过转发进行数据定位)
# max-redirects: 2
# lettuce:
# pool:
# max-idle: 10 # 连接池中的最大空闲连接
# max-wait: 500 # 连接池最大阻塞等待时间(使用负值表示没有限制)
# max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
# min-idle: 0 # 连接池中的最小空闲连接
相对比较完整的redis配置参数
spring:
redis:
host: localhost
port: 6379
username: user
password: 123456
database: 0
ssl: false
timeout: 120
connectTimeout: 120
clientName: aaa
(type,LETTUCE,JEDIS)
pool:
enable: true
maxIdle: 100
minIdle: 0
maxActive:100
maxWait:100
maxTotal: 100
maxWaitMillis: 500
testOnBorrow: false
testOnReturn: true
testWhileIdle: true
sentinel:
master: bebepay_redis
nodes:
--
password: 123456
cluster:
nodes:
--
maxRedirects:
jedis:
lettuce:
RedisTemplate和StringRedisTemplate是我们项目中常用的redis操作类。他们的关系如下图所示:
//<String, String>, 限定了只能操作key和value都是string类型的数据
public class StringRedisTemplate extends RedisTemplate<String, String> {
//构造方法中,定义序列化器stringSerializer
public StringRedisTemplate() {
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
setKeySerializer(stringSerializer);
setValueSerializer(stringSerializer);
setHashKeySerializer(stringSerializer);
setHashValueSerializer(stringSerializer);
}
......
}
Redis 支持的 Java 客户端有以下几种:
1. Jedis
2. Lettuce
3. Redisson
4. Redisson Reactive
1. Jedis
Jedis 是 Redis 的 Java 客户端。它支持完整的 Redis API,提供了良好的性能和易用性。下面是一个简单的 Jedis 示例:
import redis.clients.jedis.Jedis;
public class JedisExample {
public static void main(String[] args) {
// 连接 Redis
Jedis jedis = new Jedis("localhost", 6379);
// 设置键值对
jedis.set("foo", "bar");
// 获取键值对
String value = jedis.get("foo");
System.out.println(value);
// 关闭连接
jedis.close();
}
}
2. Lettuce
Lettuce 是一个高性能的 Redis 客户端。它使用 Netty 作为底层通信框架,并支持异步、同步和响应式编程模式。下面是一个简单的 Lettuce 示例:
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
public class LettuceExample {
public static void main(String[] args) {
// 连接 Redis
RedisClient redisClient = RedisClient.create("redis://localhost:6379");
StatefulRedisConnection connection = redisClient.connect();
RedisCommands commands = connection.sync();
// 设置键值对
commands.set("foo", "bar");
// 获取键值对
String value = commands.get("foo");
System.out.println(value);
// 关闭连接
connection.close();
redisClient.shutdown();
}
}
3. Redisson
Redisson 是一个基于 Redis 的分布式 Java 对象和服务框架。它提供了分布式锁、分布式集合、分布式对象等功能,支持异步和同步编程模式。下面是一个简单的 Redisson 示例:
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonExample {
public static void main(String[] args) {
// 连接 Redis
Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");
RedissonClient redissonClient = Redisson.create(config);
// 获取 String 对象
String value = redissonClient.getBucket("foo").get();
System.out.println(value);
// 关闭连接
redissonClient.shutdown();
}
}
4. Redisson Reactive
Redisson Reactive 是 Redisson 的响应式编程模式扩展。它可以与 Java 8 的流式 API 和 Reactor 整合,提供了基于响应式编程模式的分布式 Redis 功能。下面是一个简单的 Redisson Reactive 示例:
import org.redisson.Redisson;
import org.redisson.api.RedissonReactiveClient;
import org.redisson.config.Config;
public class RedissonReactiveExample {
public static void main(String[] args) {
// 连接 Redis
Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");
RedissonReactiveClient redissonReactiveClient = Redisson.createReactive(config);
// 获取 String 对象
redissonReactiveClient.getBucket("foo").get().subscribe(value -> System.out.println(value));
// 关闭连接
redissonReactiveClient.shutdown();
}
}
5. Spring Data Redis Reactive 技术栈
我们可以通过导入 spring-boot-starter-data-redis-reactive 依赖来集成 Spring Data Reactive Redis 模块
ReactiveRedisOperations 中定义了一批针对 Redis 各种数据结构的操作方法,如下所示。
public interface ReactiveRedisOperations<K, V> {
<HK, HV> ReactiveHashOperations<K, HK, HV> opsForHash();
<K, HK, HV> ReactiveHashOperations<K, HK, HV> opsForHash(RedisSerializationContext<K, ?> serializationContext);
ReactiveListOperations<K, V> opsForList();
<K, V> ReactiveListOperations<K, V> opsForList(RedisSerializationContext<K, V> serializationContext);
ReactiveSetOperations<K, V> opsForSet();
<K, V> ReactiveSetOperations<K, V> opsForSet(RedisSerializationContext<K, V> serializationContext);
ReactiveValueOperations<K, V> opsForValue();
<K, V> ReactiveValueOperations<K, V> opsForValue(RedisSerializationContext<K, V> serializationContext);
ReactiveZSetOperations<K, V> opsForZSet();
<K, V> ReactiveZSetOperations<K, V> opsForZSet(RedisSerializationContext<K, V> serializationContext);
…
}
在 Redis 中,常见的 ConnectionFactory 有两种,一种是传统的 JedisConnectionFactory,而另一种就是新型的 LettuceConnectionFactory。LettuceConnectionFactory 基于 Netty 创建连接实例,可以在多个线程间实现线程安全,满足多线程环境下的并发访问要求。更为重要的是,LettuceConnectionFactory 同时支持响应式的数据访问用法,它是 ReactiveRedisConnectionFactory 接口的一种实现。Lettuce 也是目前 Redis 唯一的响应式 Java 连接器。Lettuce 4.x 版本使用 RxJava 作为底层响应式流实现方案。但是,该库的 5.x 分支切换到了 Project Reactor。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
在上图中,我们同时看到 luttuce-core 组件中使用了 Project Reactor 框架中的 reactor-core 组件,这点与前面介绍的技术栈是完全一致的。
为了获取连接,我们需要初始化 LettuceConnectionFactory。LettuceConnectionFactory 类的最简单使用方法如下所示。
@Bean
public ReactiveRedisConnectionFactory lettuceConnectionFactory() {
return new LettuceConnectionFactory();
}
@Bean
public ReactiveRedisConnectionFactory lettuceConnectionFactory() {
return new LettuceConnectionFactory("localhost", 6379);
}
当然,LettuceConnectionFactory 也提供了一系列配置项供我们在初始化时进行设置,示例代码如下所示,我们可以对连接的安全性、超时时间等参数进行设置。
@Bean
public ReactiveRedisConnectionFactory lettuceConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setDatabase(database);
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
LettuceClientConfiguration.LettuceClientConfigurationBuilder lettuceClientConfigurationBuilder = LettuceClientConfiguration
.builder();
LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration,
lettuceClientConfigurationBuilder.build());
return factory;
}
有了 LettuceConnectionFactory,就可以用它来进一步初始化 ReactiveRedisTemplate。ReactiveRedisTemplate 的创建方式如下所示。与传统 RedisTemplate 创建方式的主要区别在于,ReactiveRedisTemplate 依赖于 ReactiveRedisConnectionFactory 来获取 ReactiveRedisConnection。
@Bean
ReactiveRedisTemplate<String, String>
reactiveRedisTemplate(ReactiveRedisConnectionFactory factory) {
return new ReactiveRedisTemplate<>(factory,
RedisSerializationContext.string());
}
@Bean
ReactiveRedisTemplate<String, Account> redisOperations(ReactiveRedisConnectionFactory factory) {
Jackson2JsonRedisSerializer<Account> serializer = new
Jackson2JsonRedisSerializer<>(Account.class);
RedisSerializationContext.RedisSerializationContextBuilder
<String, Account> builder = RedisSerializationContext
.newSerializationContext(new StringRedisSerializer());
RedisSerializationContext<String, Account> context =
builder.value(serializer).build();
return new ReactiveRedisTemplate<>(factory, context);
}
springboot之工程定制RedisTemplate的集群访问模式
定制RedisTemplate访问哨兵集群模式
在pom文件中引入redis的启动依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在配置文件中配置sentinel的相关信息
spring:
redis:
sentinel:
master: mymaster
nodes:
- 127.0.0.1:27001
- 127.0.0.1:27001
- 127.0.0.1:27001
- mymaster对应了sentinel的配置文件中配置的主节点名字
- 这里面配置类所有的哨兵服务器地址
配置类中添加以下配置
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}
这里的ReadFrom是配置Redis的读取策略,是一个枚举类,有以下选择
MASTER:从主节点读取
MASTER_PREFERRED:优先从master节点读取,master不可用才读取slave节点
REPLICA:从slave节点读取
REPLICA_PREFERRED:优先从slave节点读取,所有slave不可用才读取master(推荐)
至此,配置已经完成,再使用redisTemplate时读会从slave节点,写会从master节点
定制RedisTemplate访问分片集群模式
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件配置分片集群地址
spring:
redis:
cluster:
nodes: # 指定分片集群中的每个节点信息
- 127.0.0.1:7:7001
- 127.0.0.1:7:7002
- 127.0.0.1:7:7003
- 127.0.0.1:7:8001
- 127.0.0.1:7:8002
- 127.0.0.1:7:8003
配置类中配置读写分离
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}