一、背景
- 程序启动时,详细报错见下:
10:40:31.965 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘redisDistributedLocker’: Unsatisfied dependency expressed through field ‘redissonClient’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘redissonConfig’: Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder ‘spring.redis.password’ in value “${spring.redis.password}”
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘redissonConfig’: Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder ‘spring.redis.password’ in value “${spring.redis.password}”
其他报错信息,我就不贴出来了,提示我们读取不到spring.redis.password。
源码见下:
@Configuration
public class RedissonConfig {@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private String port;@Value("${spring.redis.password}")private String password;
}
二、排查过程
- 1、@Value注解使用时,需要注意属性值为空的情况
如果您尝试获取一个不存在的属性或属性值为空,则会抛出异常。
而我们开发环境搭建的redis,恰好就是没有密码的。
所以,我们的配置是:
spring:redis:host: 192.168.81.116port: 6379timeout: PT3S
预期的配置却是:
即使spring.redis.password为空,也需要把它配置一个空值。
spring:redis:host: 192.168.81.116port: 6379timeout: PT3Spassword:
你也可以修改上面的Java源码,一个冒号就可以增强程序的健壮性。
// 注意末尾加一个冒号,意味着可以为空@Value("${spring.redis.password:}")private String password;
- 2、使用@ConfigurationProperties替换@Value
@Configuration
@Data
@RefreshScope
@ConfigurationProperties(prefix = "spring.redis")
public class RedissonConfig {private String host;private String port;private String password;
}
-
3、nacos读取配置的优先级低
这里以user-service服务为例,以示说明spring boot程序读取nacos配置。对应的源码类是NacosPropertySourceBuilder.java。
它会读取四个DataId,分别是:- application.yml
- private-user-service.yml
- user-service
- user-service.yml
所以在启动的时候,不出意外,你的程序也会打印警告信息:
2023-07-28 10:35:13.202 WARN 17588 — [ main] c.a.c.n.c.NacosPropertySourceBuilder : Ignore the empty nacos configuration and get it based on dataId[user-service] & group[DEFAULT_GROUP]
不要被他误导了,以为没有读取到nacos配置。
- 4、试图把spring.redis.password配置到Nacos上, 仍旧报错
所以,你如果不想增加@Value的默认值,也不想使用@ConfigurationProperties,那么你就必须在resources/application.yml文件里配置,像下面这样:
三、总结
在我们封装jar包,或者写配置类的时候,一定要考虑配置项的可能为空情况以及动态刷新。
所以我建议你使用注解@ConfigurationProperties,并且增加@RefreshScope支持动态刷新,特别是业务上的配置项,修改后不用重启服务,做到及时刷新。