Springboot整合Redis其实很简单,只要在项目中添加redis的starter依赖就可以了。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
但在整合过程中,出现了一些莫名其妙的问题。
可能是由于springboot版本太高的原因,版本号2.7.0。
1 redisTemplate自动装配失败
首先是Spring自动注入的redisTemplate找不到。
检查springboot中的关于redis的autoconfiguration。
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
}
其中已经配置了RedisTemplate<Object,Object>类型的bean是已经存在的。即使没有经过序列化,但不应该装配失败。
强行运行,尽然没有报错,顺利执行。
可以判断出,注入应该是成功的,报错原因应该是idea的原因。idea寻找不到bean的创建声明,因为该bean是springboot运行阶段创建的。
这个报错可以不用理会,或者是使用@Resource注解进行注入。
开启springboot的debug日志输出。
logging:
level:
root: debug
在项目启动时,查看redisTemplate的创建情况。
RedisAutoConfiguration#redisTemplate matched:
- @ConditionalOnSingleCandidate (types: org.springframework.data.redis.connection.RedisConnectionFactory; SearchStrategy: all) found a single bean 'redisConnectionFactory'; @ConditionalOnMissingBean (names: redisTemplate; SearchStrategy: all) did not find any beans (OnBeanCondition)
RedisAutoConfiguration#stringRedisTemplate matched:
- @ConditionalOnSingleCandidate (types: org.springframework.data.redis.connection.RedisConnectionFactory; SearchStrategy: all) found a single bean 'redisConnectionFactory'; @ConditionalOnMissingBean (types: org.springframework.data.redis.core.StringRedisTemplate; SearchStrategy: all) did not find any beans (OnBeanCondition)
可以看出,RedisAutoConfiguration 的两个bean实例是创建成功的。因此,进一步可以确认上面的报错是idea产生的。
2 自定义redisConfig不生效。
springboot自动注入的redisTemplate是没有经过序列化处理的,它使用的是默认的JDK序列化处理。在存储任意值时,会出现乱码情况。
例如,使用默认的redisTemplate存储键值对{'xcc','123'}。
redisTemplate.opsForValue().set("xcc","123");
而在redis中最终呈现的效果如下。
在键与值之前都出现了\xAC\xED\x00\x05t\x00\x03前缀,这并不符合使用redis时的期望。这是因为使用的默认的JDK序列化器造成的。
同时,我们在使用redis时,通常使用的是RedisTemplate<String,Object>类型,这需要我们手动创建。同时,我们也需要在存储时,对数据进行序列化处理,这些可以一起进行。
Redis的手动配置如下。
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> myRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
//jackson序列化器
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//该方法已弃用
//om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(om);
//字符串序列化器
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key与hashkey的序列化方式
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
//value与hashvalue的序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
}
其中又有报错。
与之前的报错类似,初步怀疑还是idea造成的。
直接执行测试方法,报错,提示找不到RedisTemplate<String, Object>类型的bean。
在自定义的RedisConfig 代码中打断点,发现并没有执行,说明自定义的redisConfig并没有生效。
最后的解决方案:继承RedisAutoConfiguration类。
继承之后,所有问题迎刃而解,redisConnectionFactory 也能访问到不报错了。