溫馨提示:圖片有點小,可以放大頁面進行查看...
問題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 {@Autowiredprivate RedissonConnectionFactory fa;@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private Integer port;@Value("${spring.redis.password}")private String password;@Beanpublic 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;}@Beanpublic 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 {@Autowiredprivate RedisConnectionFactory factory;@Beanpublic 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