从 Spring Boot 2.x 开始 Lettuce 已取代 Jedis 成为首选 Redis 的客户端。固然 Spring Boot 2.x 仍然支持 Jedis,而且你能够任意切换客户端。java
Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。多个线程能够共享一个链接实例,而没必要担忧多线程并发问题。它基于优秀 Netty NIO 框架构建,支持 Redis 的高级功能,如 Sentinel、集群、流水线、自动从新链接和 Redis 数据模型redis
Jedis 在实现上是直接链接的 redis server,若是在多线程环境下是非线程安全的,这个时候只有使用链接池,为每一个 Jedis 实例增长物理链接。spring
Lettuce 的链接是基于 Netty 的,链接实例 (StatefulRedisConnection) 能够在多个线程间并发访问,应为 StatefulRedisConnection 是线程安全的,因此一个链接实例 (StatefulRedisConnection) 就能够知足多线程环境下的并发访问,固然这个也是可伸缩的设计,一个链接实例不够的状况也能够按需增长链接实例。 数据库
通常须要4步apache
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lettuce pool 缓存链接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
复制代码
# redis 服务端相关配置
# 服务器地址
spring.redis.host=localhost
# 端口号
spring.redis.port=6379
# 密码,默认为 null
spring.redis.password=
# 使用的数据库,默认选择下标为0的数据库
spring.redis.database=0
# 客户端超时时间,默认是2000ms
spring.redis.timeout=2000ms
## jedis 客户端配置(从 Spring Boot 2.x 开始,再也不推荐使用 jedis 客户端)
## 创建链接最大等待时间,默认1ms,超出该时间会抛异常。设为-1表示无限等待,直到分配成功。
#spring.redis.jedis.pool.max-wait=1ms
## 最大连链接数,默认为8,负值表示没有限制
#spring.redis.jedis.pool.max-active=8
## 最大空闲链接数,默认8。负值表示没有限制
#spring.redis.jedis.pool.max-idle=8
## 最小空闲链接数,默认0。
#spring.redis.jedis.pool.min-idle=0
# lettuce 客户端配置(从 Spring Boot 2.x 开始,推荐使用 lettuce 客户端)
# 创建链接最大等待时间,默认1ms,超出该时间会抛异常。设为-1表示无限等待,直到分配成功。
spring.redis.lettuce.pool.max-wait=1ms
# 最大连链接数,默认为8,负值表示没有限制
spring.redis.lettuce.pool.max-active=8
# 最大空闲链接数,默认8。负值表示没有限制
spring.redis.lettuce.pool.max-idle=8
# 最小空闲链接数,默认0。
spring.redis.lettuce.pool.min-idle=0
# 设置关闭链接的超时时间
spring.redis.lettuce.shutdown-timeout=100ms
复制代码
RedisTemplate 是 spring 为咱们提供的 redis 操做类,经过它咱们能够完成大部分 redis 操做。json
只要咱们引入了 redis 依赖,并将 redis 的链接信息配置正确,springboot 就会根据咱们的配置会给咱们生成默认 RedisTemplate。缓存
可是默认生成的 RedisTemplate 有两个地方不是很符合平常开发中的使用习惯安全
RedisTemplate<K, V>
接收的key
和value
为泛型,常常须要类型转换,直接使用不是很方便对于第一个问题,通常习惯将 RedisTemplate<K, V>
改成 RedisTemplate<String, Object>
,即接收的 key
为 String 类型,接收的 value
为 Object 类型 对于第二个问题,通常会把数据序列化为 json 格式,而后存储到 redis 中,序列化成 json 格式还有一个好处就是跨语言,其余语言也能够读取你存储在 redis 中的内容springboot
为了实现上面两个目的,咱们须要自定义本身的 RedisTemplate。bash
以下,建立一个 config 类,在里面配置 自定义的 RedisTemplate
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
// 控制配置类的加载顺序,先加载 RedisAutoConfiguration.class 再加载该类,这样才能覆盖默认的 RedisTemplate
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig {
/**
* 自定义 redisTemplate (方法名必定要叫 redisTemplate 由于 @Bean 是根据方法名配置这个bean的name的)
* 默认的 RedisTemplate<K,V> 为泛型,使用时不太方便,自定义为 <String, Object>
* 默认序列化方式为 JdkSerializationRedisSerializer 序列化后的内容不方便阅读,改成序列化成 json
*
* @param redisConnectionFactory
* @return
*/
@Bean
RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 配置 json 序列化器 - Jackson2JsonRedisSerializer
Jackson2JsonRedisSerializer jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSerializer.setObjectMapper(objectMapper);
// 建立并配置自定义 RedisTemplateRedisOperator
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// 将 key 序列化成字符串
template.setKeySerializer(new StringRedisSerializer());
// 将 hash 的 key 序列化成字符串
template.setHashKeySerializer(new StringRedisSerializer());
// 将 value 序列化成 json
template.setValueSerializer(jacksonSerializer);
// 将 hash 的 value 序列化成 json
template.setHashValueSerializer(jacksonSerializer);
template.afterPropertiesSet();
return template;
}
}
复制代码
虽然 RedisTemplate 已经对 redis 的操做进行了必定程度的封装,可是直接使用仍是有些不方便,实际开发中,通常会对 RedisTemplate 作近一步封装,造成一个简单、方便使用的Redis 操做类。
固然你也能够选择不封装,看我的喜爱。
具体的封装类就不展现了,每一个人都有本身的封装方式,没有统一的标准。
Spring Cache 是 Spring 为缓存场景提供的一套解决方案。经过使用 @CachePut
、@CacheEvict
、@Cacheable
等注解实现对缓存的,存储、查询、删除等操做
当咱们引入了 spring-boot-starter-data-redis
后,只要在带有@Configuration
类上使用 @EnableCaching
注解 Spring Cache 就会被“激活”。
Spring Cache 会为咱们配置默认的缓存管理器和key生成器,可是缓存管理器对缓存的序列化和key生成器生成的key,不易阅读。建议自定义缓存管理器和key生成器
若是用不上 Spring Cache ,能够不用管。
注意:Spring Cache 并非只能使用 Redis 做为缓存容器,其余例如 MemCache 等缓存中间件,都支持。
## spring cache 配置
# 使用的缓存的类型
spring.cache.type=redis
# 经过 spring cache 注解添加的缓存 的到期时间,单位秒(这是一个自定义属性)
cache.expireTime=60
复制代码
最重要的就是指定使用的缓存的类型
另外是一个自定义的变量,后面配置缓存管理器会用到
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
import java.time.Duration;
@Configuration
// 开启 Spring Cache
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Value("${cache.expireTime}")
// 缓存超时时间
private int cacheExpireTime;
/**
* 配置@Cacheable、@CacheEvict等注解在没有指定Key的状况下,key生成策略
* 该配置做用于缓存管理器管理的全部缓存
* 最终生成的key 为 cache类注解指定的cacheNames::类名:方法名#参数值1,参数值2...
*
* @return
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
sb.append(":");
sb.append(method.getName());
sb.append("#");
for (Object obj : params) {
sb.append(obj.toString());
sb.append(",");
}
return sb.substring(0, sb.length() - 1);
}
};
}
/**
* 配置缓存管理器
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
// 配置 json 序列化器 - Jackson2JsonRedisSerializer
Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSerializer.setObjectMapper(objectMapper);
//关键点,spring cache 的注解使用的序列化都从这来,没有这个配置的话使用的jdk本身的序列化,实际上不影响使用,只是打印出来不适合人眼识别
RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
// 将 key 序列化成字符串
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
// 将 value 序列化成 json
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSerializer))//value序列化方式
// 设置缓存过时时间,单位秒
.entryTtl(Duration.ofSeconds(cacheExpireTime))
// 不缓存空值
.disableCachingNullValues();
return RedisCacheManager.builder(factory)
.cacheDefaults(cacheConfig)
.build();
}
}
复制代码
网上 Spring Boot 集成 redis 的教程大多都是,将 redis 和 spring cache 一块配置,很容易让人产生误解。
其实 redis 和 spring cache 是两个不一样的东西,因此,上面的教程我特地分为了两个配置文件。
你能够只使用 redis 而不使用 spring cache,也能够反过来。
那为何二者常常放在一块儿去讨论呢?
缘由在于二者也有必定的联系
站在 reids 的角度看,spring cache 提供了一种便捷的操做 reids 的途径,为缓存场景提供了优秀的解决方案。
站在 spring cache 的角度看, reids 提供了一种缓存容器,能够把缓存放在 reids 中。
缓存管理器对 reids 的操做也是经过 redisTemplate 实现的。