外部属性的 Spring ConditionalOnProperty

Aer*_*ith 7 java configuration spring properties spring-boot

似乎 ConditionalOnProperty 仅适用于类路径中的属性,如资源文件夹中的 application.properties。我需要一个最终用户可以通过外部属性打开和关闭的属性。一个例子非常简单:

配置类,读取外部属性。Sys.out 显示它正在正确读取文件。

@Configuration
@EnableAutoConfiguration
@PropertySource("file:/Users/end.user/MyApp/config/MyApp.properties")
public class PropertyConfigurer {
    @Value("${featureOne}")
    private String featureOne;

    @PostConstruct
    public void init() {
        System.out.println("FeatureOne : " + featureOne);
    }
}
Run Code Online (Sandbox Code Playgroud)

要素类,如果通过 ConditionalOnProperty 启用该属性,则该组件类将被放入应用程序上下文中以便能够使用,否则永远不会实例化该组件。

@Component
@ConditionalOnProperty(name="featureOne", havingValue = "true")
public class FeatureOne {
    @PostConstruct
    public void init() {
        System.out.println("Feature initialized");
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您可以想象的那样,由于“featureOne”属性在构造此类之后才可用于 spring 上下文,因此我永远不会看到“功能已初始化”。如果有某种方法可以在类实例化时强制来自 @PropertySource 的属性可用于 spring 上下文。还是有其他方式?我也尝试过 @DependsOn 来自 FeatureOne 的 PropertyConfigurer,但有趣的是,这也不起作用。

pvp*_*ran 9

似乎 ConditionalOnProperty 仅适用于类路径中的属性,如资源文件夹中的 application.properties。

不完全是。它也适用于外部文件,前提是它们在使用spring.config.location选项运行期间被指定为程序参数。

--spring.config.location=file:/Users/end.user/MyApp/config/MyApp.properties
Run Code Online (Sandbox Code Playgroud)

问题是@PropertySource正在按org.springframework.context.annotation.ConfigurationClassParser::processPropertySource方法读取。并且@ConditionalOnProperty正在验证org.springframework.boot.autoconfigure.condition.OnPropertyCondition::getMatchOutcome方法中。
如果在这两个地方进行调试,您会发现先执行 getMatchOutcome,然后再执行 processPropertySource。因此您的条件不适用于@PropertySource.

但是,如果您将应用程序作为 运行java -jar abc.jar --spring.config.location=file:/Users/end.user/MyApp/config/MyApp.properties,那么这些属性会添加到 context.environment 中,因此@ConditionalOnProperty可以正常工作。

如果有某种方法可以在类实例化时强制来自 @PropertySource 的属性可用于 spring 上下文

我不确定是否有任何方法可以做到这一点。但是考虑到您的要求(我需要一个最终用户可以通过外部属性打开和关闭的属性),使用spring.config.location将是一个谨慎的选择。