Spring中如何用@Value动态获取属性?现有方案遇Bean解析异常
当前方案的问题
你当前的写法存在SpEL与占位符解析顺序的问题:Spring会优先解析${}格式的占位符,此时里面嵌套的#{authAppConfiguration.appName}还未被SpEL引擎解析为实际值,Spring会把#{authAppConfiguration.appName}.oauth.tokenUrl整个字符串当作配置键去查找,自然找不到对应配置,导致报错。
可行的实现方式
方式一:基于@ConfigurationProperties的动态前缀(推荐)
虽然你提到@ConfigurationProperties不支持SpEL,但实际上它的prefix属性支持SpEL表达式,只需确保提供前缀的Bean先初始化即可:
- 保留AuthAppConfiguration(确保它先被加载):
@Component public record AuthAppConfiguration( @Value("${app.name}") String appName ) { }
- 修改AuthConfigurationProperties,用SpEL指定动态前缀:
@Component @Validated @DependsOn("authAppConfiguration") @ConfigurationProperties(prefix = "#{authAppConfiguration.appName}.oauth") public record AuthConfigurationProperties( @NotEmpty String tokenUrl, String jwksUrl, @Valid OauthClient client, @Valid ValidationProperties validation ) { }
@DependsOn用于强制Spring先初始化authAppConfigurationBean,避免前缀解析时出现依赖未就绪的问题。
方式二:通过Environment手动绑定属性
注入Environment和AuthAppConfiguration,手动拼接配置键并绑定属性,灵活性更高:
@Component @Validated public record AuthConfigurationProperties( @NotEmpty String tokenUrl, String jwksUrl, @Valid OauthClient client, @Valid ValidationProperties validation ) { public AuthConfigurationProperties(AuthAppConfiguration authAppConfig, Environment env) { String prefix = authAppConfig.appName() + ".oauth"; // 绑定基础属性 this.tokenUrl = env.getRequiredProperty(prefix + ".tokenUrl"); this.jwksUrl = env.getProperty(prefix + ".jwksUrl"); // 绑定嵌套属性 Binder binder = Binder.get(env); this.client = binder.bind(prefix + ".client", OauthClient.class).orElseThrow(); this.validation = binder.bind(prefix + ".validation", ValidationProperties.class).orElseThrow(); } }
方式三:修正@Value的SpEL写法
如果坚持使用@Value,需要调整写法让SpEL优先执行,再通过Environment获取属性:
@Component @Validated public record AuthConfigurationProperties( @Value("#{environment.getProperty(authAppConfiguration.appName + '.oauth.tokenUrl')}") @NotEmpty String tokenUrl, @Value("#{environment.getProperty(authAppConfiguration.appName + '.oauth.jwksUrl')}") String jwksUrl, @Valid OauthClient client, @Valid ValidationProperties validation ) { // 嵌套属性client、validation需手动绑定,可参考方式二的Binder实现 }
这种写法的缺点是嵌套属性无法自动绑定,需要额外处理,不如方式一简洁。
内容的提问来源于stack exchange,提问作者Jesus Herrera
相关产品推荐
相关产品推荐

