1.说明
SpringBoot集成Redis缓存,
首先创建一个Spring Boot工程,
使用Maven向导方式创建:
SpringBoot集成Maven工程
然后引入redis的spring boot starter,
演示RedisTemplate的基本用法。
需要注意的是,
在SpringBoot1.x使用的是Jedis,
在SpringBoot2.x使用的是Lettuce。
下面演示的版本是SpringBoot2.x,
但是只使用RedisTemplate无需关注Lettuce。
2.新增pom依赖
修改pom.xml文件
增加spring-boot-starter-data-redis依赖,
以及Redis连接池commons-pool2依赖:
<!-- spring redis starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring2.X集成redis所需common-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
3.新增Redis配置类
新增配置类RedisConfig.java,
用于创建RedisTemplate实例,
注意设置Key和Value的序列化方式,
这样Redis保存的就是JSON格式的数据,
而不是看不懂的JDK序列化数据:
package com.yuwen.spring.demo.config;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 设置key序列化方式
StringRedisSerializer stringSerializer = new StringRedisSerializer();
template.setKeySerializer(stringSerializer);
// 设置value序列化方式
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
template.setValueSerializer(jsonSerializer);
// 初始化,并且填充参数默认值
template.afterPropertiesSet();
return template;
}
}
另外说下RedisTemplate的自动配置,
在RedisAutoConfiguration类中自动生成了
一个RedisTemplate和一个StringRedisTemplate,
但是RedisTemplate的泛型是<Object,Object>,
并且没有设置key及value的序列化方式,
不方便编码,需要编写类型转换的代码,
所以自定义了一个泛型为<String,Object>的RedisTemplate,
后面的代码就是注入这个RedisTemplate来使用的,
由于@ConditionalOnMissingBean注解的作用,
Spring容器中已经有了RedisTemplate对象,
这个自动配置类的RedisTemplate不会被实例化。
4.使用RedisTemplate
在业务类UserSortControllerImpl.java中,
使用Spring自动注入RedisTemplate<String, Object>,
这个业务使用Redis的Zset对用户进行排序,
按照用户的id存入Redis的有序集合,
然后按照id从小到大批量查询用户数据,
并且可以指定id开始和结束范围:
package com.yuwen.spring.demo.controller.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.RestController;
import com.google.common.collect.Lists;
import com.yuwen.spring.demo.controller.UserSortController;
import com.yuwen.spring.demo.entity.User;
@RestController
public class UserSortControllerImpl implements UserSortController {
// 保存在Redis中的user集合的key
private static final String ZSET_USER = "zset_user";
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public void createUser(User user) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
// 重复添加相同的user会覆盖
zset.add(ZSET_USER, user, user.getId());
System.out.println("add user " + user + "to redis zset_user");
}
@Override
public List<User> getAllUser(Integer min, Integer max) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
// 如果边界为空,使用负无穷和正无穷填充
if (min == null) {
min = Integer.MIN_VALUE;
}
if (max == null) {
max = Integer.MAX_VALUE;
}
Set<Object> userObjects = zset.rangeByScore(ZSET_USER, min, max);
System.out.println("getAllUser users=" + userObjects);
List<User> users = Lists.transform(new ArrayList<>(userObjects), object -> (User) object);
return users;
}
}
注意RedisTemplate的泛型不能写错,
否则Spring无法注入对应的单例,
createUser方法把用户存入Redis,并使用Id作为排序参数,
getAllUser方法按照ID访问从Redsi查询数据。
5.Object集合转换问题
getAllUser方法从Redis查询用户信息时,
返回的是Set<Object>类型,
需要转换成List<User>类型返回,
由于存入的类型一定是User,
所以Object一定能强转为User:
Set<Object> userObjects = zset.rangeByScore(ZSET_USER, min, max);
List<User> users = Lists.transform(new ArrayList<>(userObjects), object -> (User) object);
上面使用了Google Guava的Lists进行转换的,
需要在pom中增加如下依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
6.查看Redis数据
登录Redis服务端,
查看存储在zset_user中的数据,
并且输出其关联的id:
127.0.0.1:6379> zrange zset_user 0 -1 withscores
1) "{\"@class\":\"com.yuwen.spring.demo.entity.User\",\"id\":2,\"name\":\"tom\",\"birthday\":null,\"email\":null}"
2) "2"
3) "{\"@class\":\"com.yuwen.spring.demo.entity.User\",\"id\":3,\"name\":\"jack\",\"birthday\":null,\"email\":null}"
4) "3"
5) "{\"@class\":\"com.yuwen.spring.demo.entity.User\",\"id\":7,\"name\":\"sam\",\"birthday\":null,\"email\":null}"
6) "7"
可以看到输出的数据是能够看懂的,
携带其类名的JSON格式。
7.实体类User说明
Demo中使用的User.java源码如下:
package com.yuwen.spring.demo.entity;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private static final long serialVersionUID = -3301999810945119126L;
private Long id;
private String name;
private Date birthday;
private String email;
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", birthday=" + birthday + ", email=" + email + "]";
}
}
由于在RedisConfig.java中,
设置了RedisTemplate的value序列化方式为JSON,
JSON格式不要求实体类实现Serializable,
但是使用默认的JDK格式,
一定要实现序列化接口,
否则数据无法存储到Redis。
8.参考文章
springboot集成redis (Lettuce)
【深入浅出SpringBoot】RedisTemplate使用方法归纳