問題
某新項目(基於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}
重新啟動項目成功^_^!
參考
- 連接redis, 因為密碼有特殊字符#, 導致無法正常連接 https://blog.csdn.net/cainiao1412/article/details/116269700
- java uri 空格_URI 中特殊字符處理 https://blog.csdn.net/weixin_35949153/article/details/114232736