SpringBoot项目连接Redis启动报错(Unable to validate object)

问题

某新项目(基于SpringBoot)在线上部署完成后启动失败,查看错误日志如下:
Error creating bean with name 'jedisPool'...
...
Caused by: redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool
...
Caused by: java.util.NoSuchElementException: Unable to validate object
...

分析&解决

项目使用了Redis,基于Jedis封装了方便Redis操作的SpringBoot starter,里面在初始化配置时创建了ShardedJedisPool
项目使用了阿里云的应用配置管理(ACM),其中Redis连接相关参数配置在云上的yml文件中,配置了主机、端口、密码、数据库编号、超时参数等。
项目在测试环境启动正常,检查线上环境参数配置,通过阿里云的网页客户端连接Redis正常。

yml文件里Redis部分配置如下:

redis:
  host: xxx.redis.rds.aliyuncs.com
  port: 6379
  password: xxx
  database: 5

查看创建ShardedJedisPool代码如下:

String password = redisProperties.getPassword();
password = !StringUtils.isEmpty(password) ? (":" + password + "@") : "";
String redisUri = "redis://" + password + host + ":" + port + "/" + database;
JedisShardInfo shard = new JedisShardInfo(redisUri);

注意到线上环境的Redis密码有特殊字符#,查看new JedisShardInfo,点进去看是通过URI.create(host)来创建URI对象,
#通过URLEncoder.encode()编码为%23,将redis.password替换后重启项目,启动成功。

后续

项目后来引入了redisson框架,使用分布式锁。

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.5.0</version>
</dependency>

其中redisson配置如下:

redisson:
  address: redis://${spring.redis.host}:${spring.redis.port}
  password: ${spring.redis.password}
  database: ${spring.redis.database}

构建RedissonClient代码如下:

@Bean
@ConditionalOnProperty(
    name = {"redisson.address"}
)
RedissonClient redissonSingle() {
    Config config = new Config();
    config.setLockWatchdogTimeout(this.redssionProperties.getLockWatchdogTimeout());
    SingleServerConfig serverConfig = ((SingleServerConfig)config.useSingleServer().setDatabase(this.redssionProperties.getDatabase()).setAddress(this.redssionProperties.getAddress()).setTimeout(this.redssionProperties.getTimeout())).setConnectionPoolSize(this.redssionProperties.getConnectionPoolSize()).setConnectionMinimumIdleSize(this.redssionProperties.getConnectionMinimumIdleSize());
    if (StringUtils.isNotBlank(this.redssionProperties.getPassword())) {
        serverConfig.setPassword(this.redssionProperties.getPassword());
    }

    return Redisson.create(config);
}

项目启动报错,提示密码错误,注意到这里通过SingleServerConfig#setPassword来设置密码,因此不需要使用转换后的密码,直接用原密码即可。
修改redisson配置如下:

redisson:
  address: redis://${spring.redis.host}:${spring.redis.port}
  password: xxx
  database: ${spring.redis.database}

重新启动项目成功^_^!

参考

posted @ 2022-04-20 20:33  cdfive  阅读(1792)  评论(0编辑  收藏  举报