项目中同时使用Redis(lettuce)和Redisson的报错
温馨提示:图片有点小,可以放大页面进行查看...
问题1:版本冲突
直接上图,这个错表示依赖版本不匹配问题,我本地SpringBoot用的是2.7,但是Redisson版本用的3.32.5。
我们通过点击 artifactId跟进去
发现它依赖的SpringBoot版本是3.1
换成3.18.0之后就好了
大家碰到NotClassDefFoundError ,就优先考虑依赖版本问题,连类定义都没有,太离谱了...
问题2:循环依赖
这个错误还是很容易就复现出来的...
这里放大关键报错信息
我在RedisConfig中同时完成RedisTemplate和RedissonClient的初始化。
因为我通过字段注入RedissonConnectionFactory。
当其他类需要redisTemplate的时候,即依赖RedisConfig,去完成Bean注册的时候发现redisTemplate依赖RedissonConnectionFactory,而RedissonConnectionFactory依赖RedissonClient,而RedissonClient依赖RedisConfig。走了一圈,发现RedisConfig依赖RedisConfig,所以产生了循环依赖。
@Configuration
public class RedisConfig {
@Autowired
private RedissonConnectionFactory fa;
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private Integer port;
@Value("${spring.redis.password}")
private String password;
@Bean
public RedisTemplate<String, Object> redisTemplate(RedissonConnectionFactory factory) {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.setDefaultSerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
// redis为单机模式
config.useSingleServer()
.setAddress("redis://" + host + ":" + port);
return Redisson.create(config);
}
}
眼尖的朋友可能会有疑问,我为什么要将RedissonConnectionFactory作为字段,依赖注入?
其实原代码用的是RedisConnectionFactory,同时redisTemplate用的RedisConnectionFactory完成的Bean初始化。我在它的基础上加了个RedissonClient的初始化。
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory factory;
@Bean
public RedisTemplate<String, Object> redisTemplate() {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.setDefaultSerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
}
但其实,我这里不管用RedissonConnectionFactory还是RedisConnectionFactory都是一样的,最终其实用的都是 RedissonConnectionFactory....
先说答案:因为项目中引入了Redisson框架,因此Spring容器会优先使用RedissonConnectionFactory,因为会优先执行 RedissonAutoConfiguration 文件。
下面是分析过程:
我将字段注入去掉,并且方法参数改成了RedissonConnectionFactory,进行debug
跟进RedissonConnectionFactory,继续跟进getConnection方法
发现这里已经变成了redissonConnection
因为:项目中使用了Redisson,优先初始化RedissonClient,【依赖于RedissonConnectionFactory,所以RedissonConnectionFactory也初始化了】
看一下为什么RedisConnectionFactory会被替换为RedissonConnectionFactory:
跟进RedisConnectionFactory,它继承自PersistenceExceptionTranslator
查看PersistenceExceptionTranslator的引用,发现同时有RedisConnectionFactory和RedissonConnectionFactory两个Bean
这里使用的是RedissonConnectionFactory。
解决办法:
方法1:将字段注入去掉,这样的话可以打破依赖关系:
RedisConfig - > RedissonConnectionFactroy
方法2:在启动类上,添加属性 exclude ,将RedisAutoConfiguration 排除掉,这样的话,也是打破了RedisConfig -> RedissonConnectionFactory,改成了依赖RedisConnectionFactory