前面的SpringCache缓存说过在没有引入其他缓存中间件时,默认使用的是ConcurrentMapCacheManager=ConcurrentMapCache,是将数据保存在ConcurrentMap<Object, Object>
中。
在实际开发中,我们一般都会使用redis
、memcached
、ehcache
来作为缓存中间件。
整合Redis
Redis
是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。
当我们引入Reids
的starter
依赖的时候,使用RedisCacheManager
。RedisCacheManager
会帮我们创建RedisCache
来作为缓存组件,RedisCache通过操作redis缓存数据。
1、引入Redis的starter的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 连接池 - luttuce依赖该连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
2、配置yml
配置文件
spring:
redis:
host: 127.0.0.1 # Redis连接地址
port: 6379 # redis连接端口
lettuce: # 使用lettuce客户端
pool:
max-active: 8 # 连接池最大连接数(负值表示没有限制)
max-idle: 8 # 连接池的最大空闲连接
min-idle: 0 # 连接池的最小空闲连接
max-wait: -1ms # 连接池最大阻塞等待时间(赋值表示没有限制)
database: 0 # 默认使用索引为0的数据库
timeout: 5000ms # 连接超时时间
3、序列化配置
Reids默认使用的是JDK的序列化机制,我们通过RedisDesktopManager
去查看存储的数据,是无法用肉眼看出存的是什么的。
比如说我们要存一个对象进去,并且想直接肉眼看到是一个怎么样的数据,可以通过修改配置,让其以Json
的格式去保存。
创建一个配置类继承CachingConfigurerSupport
@Configuration
public class RedisConfiguration extends CachingConfigurerSupport {
/**
* 采用RedisCacheManager作为缓存管理器
* @param connectionFactory Redis连接工厂 - 配置的Luttuce,这里实际传递的就是LuttuceFactory
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory){
RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory);
return redisCacheManager;
}
/**
* 解决键值序列化问题
* @param connectionFactory Redis连接工厂
* @return
*/
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory){
RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
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);
redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
4、测试一下
// 注入RedisTemplate
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
// 向Redis中存数据
@GetMapping("/test")
public String test(){
BoundHashOperations boundHashOps = redisTemplate.boundHashOps("User");
List list = new ArrayList();
User user1 = new User("柳成荫", "男", 22);
list.add(user1);
list.add(user1);
boundHashOps.put("3",list);
return "ok";
}
// 向Redis取数据
@GetMapping("/test1")
public List test1(){
BoundHashOperations boundHashOps = redisTemplate.boundHashOps("User");
List<User> users = (List<User>) boundHashOps.get("3");
return users;
}
可以看到确实存入的是JSON序列化的结果
取出来也是没有问题的
使用Cache
上面的RedisConfiguration
中已经指定了缓存管理器为RedisCacheManager
,也就是说Cache现在是可以存到Redis中的。
1、创建POJO类
@Data
public class User implements Serializable {
private Long id;
private String name;
private String sex;
private Integer age;
public User(){}
public User(Long id,String name, String sex, Integer age) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}
}
2、创建Service类
为了方便测试,直接创建了一个Service类,并且直接通过SpringBooTest
来直接调用测试。
@Service
@CacheConfig(cacheNames = "user_cache") // 缓存名
public class UserService {
@Cacheable(key = "#id") // 缓存key
public User getUser(Long id){
System.out.println("直接获取User信息:");
User user = new User(1L,"柳成荫","男",22);
return user;
}
}
3、测试
@Autowired
private UserService userService;
@Test
public void test1(){
User user = userService.getUser(2L);
System.out.println(user);
}
4、测试结果
通过RedisDesktopManager查看存储情况。
5、可以使用自定义的Key
使用自定义Key规则,直接在RedisConfiguration
中重写KeyGenerator
方法即可,示例:
/**
* 自定义生成Key的规则
* @return
*/
@Override
public KeyGenerator keyGenerator() {
return new KeyGeneratorImpl();
}
/**
* 生成Key的规则
*/
private class KeyGeneratorImpl implements KeyGenerator{
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName()).append("."); // 追加类名
sb.append(method.getName()).append("(");
for (Object object : params){
sb.append(object.toString()).append(",");
}
sb.deleteCharAt(sb.length() - 1);
sb.append(")");
System.out.println("调用了Redis缓存Key:" + sb.toString());
return sb.toString();
}
}
在Service类上或类中方法上指定缓存名
即可:
@Service
public class UserService {
@Cacheable(value = "abc") // 缓存名:abc
public User getUser(Long id){
System.out.println("直接获取User信息:");
User user = new User(1L,"柳成荫","男",22);
return user;
}
}
测试之后,结果如下:
序列化总结
①JdkSerializationRedisSerializer
是默认序列化方式,是最简单的也是最安全的,只要实现了Serializer接口,实体类型,集合,Map等都能序列化与反序列化,但缺陷是序列化数据很多,会对redis造成更大压力,且可读性和跨平台基本无法实现
②Jackson2JsonRedisSerializer
用的是json
的序列化方式,能解决JdkSerializationRedisSerializer
带来的缺陷。
③jdk
的序列化方式字符串会比json
序列化文本大5倍。
SpringCache+Redis可以参考:SpringBoot整合Redis、SpringDataRedis最佳实践