spring boot 集成 redis

2333

记录一下

一、关于 spring-redis

spring-data-redis 针对 jedis 提供了如下功能:

  1. 连接池自动管理,提供了一个高度封装的 RedisTemplate 类
  2. 针对 jedis 客户端中大量 api 进行了归类封装,将同一类型操作封装为 operation 接口
ValueOperation: 简单 K-V 操作
SetOperation: set类型数据操作
ZSetOperations: zset 类型数据操作
HashOperations: 针对 map 类型的数据操作
ListOperations: 针对 list 类型的数据操作

RedisTemplate中定义了5种数据结构操作

  • redisTemplate.opsForValue(): 操作字符串
  • redisTemplate.opsForHash(): 操作hash
  • redisTemplate.opsForList(): 操作list
  • redisTemplate.opsForSet(): 操作set
  • redisTemplate.opsForZSet(): 操作有序set

二、Maven依赖

本文所采用的是 SpringBoot2.X 的版本,在 pom 中引入 redis 及其 jar 包

<!-- spring boot redis 缓存引入 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.1.5.RELEASE</version> </dependency> <!-- lettuce pool 缓存连接池 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <!-- jackson json 优化缓存对象序列化 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.6</version> </dependency>

三、application.properties中加入redis相关配置

redis 目前常用的连接池有jedis 和 lettuce,这里我使用的是 lettuce 连接池。

# Redis服务器地址
spring.redis.host=xxxxx
# Redis端口
spring.redis.port=6379
# Redis 密码
spring.redis.password=xxxxx
# Redis数据库索引(默认为0)
spring.redis.database=3
# 连接池最大连接数(使用负值表示没有限制) 
spring.redis.lettuce.pool.max-active=10
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.pool.max-wait=4
# 连接超时时间(毫秒)
spring.redis.timeout=4000

到这里已经算是配置成功了,接下来我们简单使用下,先创建个 Controller 控制器。

@RestController @RequestMapping("/api/redis") public class RedisController { @Autowired private RedisTemplate redisTemplate; /** * 查询所有列表 * @return */ @GetMapping("/set") public Object set(@RequestParam("key") String key, @RequestParam("value") String value) { redisTemplate.opsForValue().set(key, value); return "ok"; } }

在浏览器输入:

http://127.0.0.1:8088/api/redis/set?key=name&value=yxf233

使用 spring boot redis 默认的配置类,你会发现通过 redis 客户端链接查看完全是乱码的,阅读性非常差。
redis默认链接.png

四、写一个 redis 配置类

1)、关于 redisTemplate 的自动配置
源码

@Configuration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean public StringRedisTemplate stringRedisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }

通过源码可以看出,SpringBoot自动帮我们在容器中生成了一个 RedisTemplate 和一个 StringRedisTemplate。但是这个 RedisTemplate 的泛型是 <Object, Object>,写代码不方便,需要写好多类型转换的代码,我们需要一个泛型为 <String, Object> 形式的 RedisTemplate。并且这个 RedisTemplate 没有设置数据存在Redis时,key及value的序列化方式。

看到这个 @ConditionalOnMissingBean 注解后,就知道如果 Spring 容器中有了 RedisTemplate 对象了,这个自动装配的 RedisTemplate 不会实例化,因此我们可以直接自己写个配置类,配置RedisTemplate。

2)、既然自动配置不好用,就重新配置一个 RedisTemplate
代码如下:

@EnableCaching @Configuration public class RedisConfig extends CachingConfigurerSupport { /** * 自定义缓存 key 的生成策略,默认的生成策略是看不懂的(乱码内容), * 通过 Spring 的依赖注入特性进行自定义的配置注入,并且此类是一个配置类可以更多程度的自定义配置 * @return */ @Override public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } /** * 缓存配置管理器 * @param factory * @return */ @Bean public CacheManager cacheManager(LettuceConnectionFactory factory) { // 以锁写入的方式创建 RedisCacheWriter 对象 RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory); /** * 设置 CacheManager 的 value 序列化方式为 JdkSericalizationRedisSerializer * 但是其实 RedisCacheConfiguration 默认就是使用 StringRedisSerializer 序列化key, JdkSerializationRedisSerializer 序列化 value */ // 创建默认缓存配置对象 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); RedisCacheManager cacheManager = new RedisCacheManager(writer, config); return cacheManager; } /** * 获取还操作助手对象 * @param factory * @return */ @Bean public RedisTemplate<String, String> redisTemplate(LettuceConnectionFactory factory) { // 创建 redis 缓存操作助手 RedisTemplate 对象 StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(factory); /** * 以下代码将 RedisTemplate 的 value 序列化方式由 JdkSerializationRedisSerializer 更换为 Jackson2JsonRedisSerializer * 此种序列化方式结果清晰、容易阅读、存储字节少、速度快 */ Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); jackson2JsonRedisSerializer.setObjectMapper(om); template.setValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); // StringRedisTemplate 是 RedisTempLate<String, String> 的子类 return template; } }

更多的 RedisTemplate 可以查看 RedisTemplate Api总结

3)、controller控制器

@RestController public class Hello { @Autowired private RedisTemplate redisTemplate; @GetMapping("/api/test1/hello") public String say(@RequestParam String key, @RequestParam String value) { redisTemplate.opsForValue().set(key, value); return "ok"; } @GetMapping("/api/test1/hello/get") public String say(@RequestParam String key) { String result = (String)redisTemplate.opsForValue().get(key); return result; } }

参考文章