引入Redisson可能会出现项目启动失败问题解决
·
问题1:需要注意Redisson版本和spring-boot版本一致,我使用的是spring-boot 2.1.3 对应的Redisson 3.9.1不然会报错
java.lang.NoClassDefFoundError: org/springframework/data/redis/connection/RedisStreamCommands
at org.redisson.spring.data.connection.RedissonConnectionFactory.getConnection(RedissonConnectionFactory.java:111)
at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:132)
at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:95)
at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:82)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:211)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:184)
at org.springframework.data.redis.core.RedisTemplate.hasKey(RedisTemplate.java:769)
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.9.1</version>
</dependency>
问题2:Redisson自己会启动一个Redisson连接池,尝试连接redis,项目启动的时候就会连接,这时候如果k8s初始化的pod节点网络不通可能会出现问题,因为redis连接不上(说是我们的是海外服务器的原因,网络不稳定),项目报错,导致起不起来,然后pod会一直重启,因为运维层次不了解他们设置的k8s原理,需要在短时间解决,提供了下面的方案解决,后来也没有再出现这个问题,启动报错
1)自己重新空实现了一个RedissonClient
/**
* @ClassName RedissonClientTemporary
* @Decription 只是在初始化时候使用一下,之后就会被替换
*/
public class RedissonClientTemporary implements RedissonClient{
}
2)然后将这个空实现注入到spring容器,为了给其它使用到RedissonClient,作为属性初始化时候不报错
@Configuration
public class RedissonConfig {
/**
* 配置一个临时的对象到spring容器中,不使用
* @return 一个RedissonClient的实现
*/
@Bean
public RedissonClient redissonClient() {
RedissonClient redissonClient = new RedissonClientTemporary();
return redissonClient;
}
}
3)项目启动完成使用一个监听事件,放入Redisson替换RedissonClient的实现,然后初始化一下,这里可能还是会连接报错但是不影响,因为已经放入了spring容器,如果这里连接失败,他也就不会再次尝试连接了,直到你再次使用它时候才会再次调用创建连接(那会redis就已经可用,其实redis还不可用,我们使用降级策略也可以,那会使用本地缓存或者数据库等)
/**
* @ClassName ApplicationLoadRedissonListener
* @Decription 项目启动完成,增加一个监听器,替换spring容器里面的redissonClient的对象,进行切换成redisson
*/
@Component
public class ApplicationLoadRedissonListener implements ApplicationListener<ApplicationReadyEvent> {
private static final Logger log = LoggerFactory.getLogger(ApplicationLoadRedissonListener.class);
@Autowired
ConfigurableApplicationContext configurableApplicationContext;
@Autowired
private RedisProperties redisProperties;
@Value("${spring.redis.redisson.singleServerConfig.subscriptionsPerConnection}")
private Integer subscriptionsPerConnection;
@Value("${spring.redis.redisson.singleServerConfig.connectionPoolSize}")
private Integer connectionPoolSize;
@Value("${spring.redis.redisson.singleServerConfig.connectionMinimumIdleSize}")
private Integer connectionMinimumIdleSize;
@Value("${spring.redis.redisson.singleServerConfig.subscriptionConnectionPoolSize}")
private Integer subscriptionConnectionPoolSize;
@Value("${spring.redis.redisson.singleServerConfig.subscriptionConnectionMinimumIdleSize}")
private Integer subscriptionConnectionMinimumIdleSize;
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
try{
//加载一些基本的redis基础配置
Config config = new Config();
String address = "redis://" + redisProperties.getHost() + ":" + redisProperties.getPort();
SingleServerConfig serverConfig = config.useSingleServer();
serverConfig.setAddress(address);
serverConfig.setDatabase(redisProperties.getDatabase());
if (!StringUtils.isEmpty(redisProperties.getPassword())) {
serverConfig.setPassword(redisProperties.getPassword());
}
serverConfig.setTimeout((int)redisProperties.getTimeout().toMillis());
//加载redisson一些特殊配置
serverConfig.setConnectionPoolSize(connectionPoolSize);
serverConfig.setConnectionMinimumIdleSize(connectionMinimumIdleSize);
serverConfig.setSubscriptionConnectionMinimumIdleSize(subscriptionConnectionMinimumIdleSize);
serverConfig.setSubscriptionConnectionPoolSize(subscriptionConnectionPoolSize);
serverConfig.setSubscriptionsPerConnection(subscriptionsPerConnection);
log.info("加载 redisson配置信息 {}", JsonUtil.of(serverConfig));
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Redisson.class);
beanDefinitionBuilder.addConstructorArgValue(config);
String redissonClientName = RedissonClient.class.getSimpleName().substring(0,1).toLowerCase() + RedissonClient.class.getSimpleName().substring(1);
Object redissonClient = configurableApplicationContext.getBean(redissonClientName);
log.info("初次放入的redissonClient实现对象:{}", redissonClient.getClass().getName());;
//创建一个Redisson对象
BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) configurableApplicationContext;
beanDefinitionRegistry.registerBeanDefinition(redissonClientName, beanDefinitionBuilder.getBeanDefinition());
//这里相当于初始化加载使用
redissonClient = configurableApplicationContext.getBean(redissonClientName);
log.info("最终放入的redissonClient实现对象:{}", redissonClient.getClass().getName());
}catch (Exception e){
log.info("ApplicationLoadRedissonListener/onApplicationEvent/RedissonClient/Exception:[{}]", e.getMessage());
}
}
}
# redisson 连接配置
# 单个连接最大订阅数量
spring.redis.redisson.singleServerConfig.subscriptionsPerConnection=5
# 连接池大小
spring.redis.redisson.singleServerConfig.connectionPoolSize=8
# 最小空闲连接数
spring.redis.redisson.singleServerConfig.connectionMinimumIdleSize=4
# 发布和订阅连接池大小
spring.redis.redisson.singleServerConfig.subscriptionConnectionPoolSize=8
# 发布和订阅连接的最小空闲连接数
spring.redis.redisson.singleServerConfig.subscriptionConnectionMinimumIdleSize=1
更多推荐
已为社区贡献1条内容
所有评论(0)