Spring Config Server中@Value注入返回null问题求助
配置服务器可正常返回配置,其他配置项能正常获取,但JwtUtil类中通过@Value注入的jwt.secret和jwt.expiration始终为null。推测与@PostConstruct有关,尝试过用Environment替代@Value、构造注入、调整@PostConstruct位置等方案均无效,仅当配置放在Application.yml或Bootstrap.yml中时才能正常获取。
配置服务器返回内容
{ "name": "auth-service", "profiles": [ "jdbc" ], "label": "1.0", "version": null, "state": null, "propertySources": [ { "name": "auth-service-jdbc", "source": { "spring.datasource.url": "jdbc:mysql://x.x.x.x:3306/test?useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false", "spring.datasource.username": "xxxx", "spring.datasource.password": "xxxxx", "jwt.secret": "xxxxxxx", "jwt.expiration": "86400" } } ] }
问题代码
@Component public class JwtUtil { @Value("${jwt.secret}") String secret; @Value("${jwt.expiration}") String expirationTime; private Key key; @PostConstruct public void init() { this.key = Keys.hmacShaKeyFor(secret.getBytes()); } }
核心原因
问题本质是配置加载时机不匹配:Spring Cloud Config的远程配置加载流程晚于@PostConstruct的执行时机。当@PostConstruct方法触发时,远程配置还未拉取完成,导致@Value注入的属性仍为null。而本地的Application.yml/Bootstrap.yml属于启动初期加载的配置,因此能正常注入。
可行解决方法
改用
@ConfigurationProperties绑定配置
这种方式支持配置延迟绑定与刷新,适配远程配置的加载节奏:@Component @ConfigurationProperties(prefix = "jwt") public class JwtUtil { private String secret; private String expiration; private Key key; @PostConstruct public void init() { if (secret != null) { this.key = Keys.hmacShaKeyFor(secret.getBytes()); } } // 必须添加getter/setter以支持属性绑定 public String getSecret() { return secret; } public void setSecret(String secret) { this.secret = secret; } public String getExpiration() { return expiration; } public void setExpiration(String expiration) { this.expiration = expiration; } public Key getKey() { return key; } }延迟Bean初始化
通过@Lazy注解让JwtUtil在首次被使用时才初始化,此时远程配置已加载完成:@Component @Lazy public class JwtUtil { @Value("${jwt.secret}") String secret; @Value("${jwt.expiration}") String expirationTime; private Key key; @PostConstruct public void init() { this.key = Keys.hmacShaKeyFor(secret.getBytes()); } }注意:需确保
JwtUtil的首次调用发生在远程配置加载完成之后。监听配置刷新事件
通过监听配置变更事件,在远程配置加载/刷新后重新初始化密钥:@Component public class JwtUtil implements ApplicationListener<EnvironmentChangeEvent> { @Value("${jwt.secret}") String secret; @Value("${jwt.expiration}") String expirationTime; private Key key; @PostConstruct public void init() { refreshKey(); } private void refreshKey() { if (secret != null) { this.key = Keys.hmacShaKeyFor(secret.getBytes()); } } @Override public void onApplicationEvent(EnvironmentChangeEvent event) { // 仅当jwt相关配置变更时刷新密钥 if (event.getKeys().stream().anyMatch(k -> k.startsWith("jwt."))) { refreshKey(); } } }恢复Bootstrap上下文加载(Spring Cloud 2020.0+)
若使用Spring Cloud 2020.0及以后版本,默认禁用了Bootstrap上下文,需手动引入依赖让远程配置在启动初期加载:<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>
内容的提问来源于stack exchange,提问作者Hybrid1969

