Spring Boot 配置属性的未解析占位符验证

Unresolved Placeholder Validation for Spring Boot Configuration Properties

提问人:Joe Taylor 提问时间:4/19/2017 更新时间:9/15/2023 访问量:4764

问:

给定一些具有不可解析占位符的应用程序配置,如下所示application.yml

my:
  thing: ${missing-placeholder}/whatever

当我使用注解时,配置文件中的占位符会得到验证,因此在本例中:@Value

package com.test;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class PropValues {
    @Value("${my.thing}") String thing;
    public String getThing() { return thing; }
}

我得到一个.这是因为该值是由 直接设置的,并且没有任何东西可以捕获 引发的异常IllegalArgumentException: Could not resolve placeholder 'missing-placeholder' in value "${missing-placeholder}/whatever"AbstractBeanFactory.resolveEmbeddedValuePropertyPlaceholderHelper.parseStringValue

但是,在寻求移动到样式时,我注意到缺少此验证,例如在本例中:@ConfigurationProperties

package com.test;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

@ConfigurationProperties(prefix = "my")
public class Props {
    private String thing;
    public String getThing() { return thing; }    
    public void setThing(String thing) { this.thing = thing; }
}

没有例外。我可以看到使用注释捕获异常并将无效值收集到其内部映射中。后续数据绑定不会检查未解析的占位符。PropertySourcesPropertyValues.getEnumerableProperty// Probably could not resolve placeholders, ignore it here

我检查了简单地将 and 注释应用于类和字段无济于事。@Validated@Valid

有没有办法保留在绑定的未解析占位符上引发异常的行为?ConfigurationProperties

Spring 验证 配置 spring-boot-configuration

评论

1赞 M. Deinum 4/19/2017
你应该但是在类和/或字段上,为了使验证工作,你必须在类路径上有一个JSR-303验证器,如.仅添加注释不会产生任何结果。@Validated@NotNull@NotEmptyhibernate-validation@Validation
0赞 svaponi 5/14/2019
有人找到解决方案了吗?

答:

-1赞 DeejonZ 4/19/2017 #1

我在 10 分钟前遇到了同样的问题! 尝试在配置中添加此 bean:

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
        propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(true);
        return propertySourcesPlaceholderConfigurer;
    }

评论

0赞 Joe Taylor 4/19/2017
很好的发现,但实际上这是相反问题的解决方案。我不想隐藏错误,我想保留它。
1赞 DeejonZ 4/19/2017
您必须手动执行此操作,使属性类实现并覆盖方法,您可以通过反射检查每个字段的值,并在它们为 null 时抛出异常。InitializingBeanafterPropertiesSet()
0赞 Joe Taylor 4/20/2017
这听起来不是很优雅,除了属性不会以 null 结束之外,它们最终的占位符值仍嵌入在字符串中。
0赞 DeejonZ 4/20/2017
是的,我同意,不是很优雅。如果我找到更好的方法,我会告诉你。
0赞 svaponi 5/14/2019
我不敢相信 afterPropertiesSet() 是我们拥有的最好的:'(
0赞 svaponi 5/14/2019 #2

显然没有更好的解决方案。至少这比 afterPropertiesSet() 更好。

@Data
@Validated // enables javax.validation JSR-303
@ConfigurationProperties("my.config")
public static class ConfigProperties {
    // with @ConfigurationProperties (differently than @Value) there is no exception if a placeholder is NOT RESOLVED. So manual validation is required!
    @Pattern(regexp = ".*\$\{.*", message = "unresolved placeholder")
    private String uri;
    // ...
}

更新:我第一次弄错了正则表达式。它与整个输入(而不仅仅是 )匹配。java.util.regex.Matcher#find()

0赞 Zaid 5/11/2021 #3

要传入注解的正确正则表达式是@Pattern^(?!\\$\\{).+

@Validated
@ConfigurationProperties("my.config")
public class ConfigProperties {
    
    @Pattern(regexp = "^(?!\\$\\{).+", message = "unresolved placeholder")
    private String uri;
    // ...
}
0赞 Archimedes Trajano 9/15/2023 #4

如果您使用的是 on,您可以设置默认值。您可以使用以下命令:@ConfigurationPropertiesProps

@Value("#{props.getThing()}")
String theThing;

这也适用于其他 SPeL 上下文,例如Scheduled

@Scheduled(fixedDelayString = "#{@dbConfigurationProperties.getExpirationCheckDelayInMs()}")
void cleanup() {
...
}