Spring Java 有没有办法动态获取属性?

问题描述 投票:0回答:1

这样做的目的是使用 @Value 动态获取属性。

我的申请

application.yml

app:
    name: my-app-scv

my-app-svc: # This value will be dynamic acoording to each other app implementing Auth-Library
    oauth:
        tokenUrl: https://anOAuthImpl.com
        jwksUrl: https://anOAuthImpl.com/jwks
        validation:
            url: https://anOAuthImpl.com/validate/
        client:
            id: client_id
            secret: secret

授权库

AuthConfigurationProperties java记录

@Component
@Validated
public record AuthConfigurationProperties(
        @Value("${#{authAppConfiguration.appName}.oauth.tokenUrl}}")
        @NotEmpty
        String tokenUrl,
        @Value("${#{authAppConfiguration.appName}.oauth.jwksUrl}")
        String jwksUrl,
        @Valid
        OauthClient client,
        @Valid
        ValidationProperties validation
) {

}

AuthAppConfiguration java记录

@Component
public record AuthAppConfiguration(
        @Value("${app.name}")
        String appName
) {
}

这些更改之前的解决方案有

@ConfigurationProperties
,但不支持 SpEL。

这是正确的方法还是有更简单的方法?另外,我的豆子也有问题

AuthAppConfiguration
; Spring无法正确解析bean。

到目前为止,我正在尝试在另一个 bean 中设置应用程序之外的值,以便 SpEL 首先计算表达式,然后 @Value 选取预期的属性。

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder '#{authAppConfiguration.appName}.oauth.tokenUrl' in value "${#{authAppConfiguration.appName}.oauth.tokenUrl}"

java spring properties
1个回答
0
投票

您有多种选择来动态获取环境变量。

选项 1:在构造函数中使用
Environment
bean 或
PostConstruct
来执行自定义逻辑。

这可能是最简单的,因此也是适合您情况的最佳解决方案

  1. 自动装配
    Environment
    豆。
  2. 从中提取变量:
@Component
@Validated
public class AuthConfigurationProperties {

    @NotEmpty
    private String tokenUrl;
    private String jwksUrl;
    @Valid
    private OauthClient client;
    @Valid
    private ValidationProperties validation;

    public AuthConfigurationProperties(OauthClient client, ValidationProperties validation, Environment environment) {
        this.client = client;
        this.validation = validation;
        
        String appName = environment.getProperty("authAppConfiguration.appName");
        this.tokenUrl = environment.getProperty("%s.oauth.tokenUrl".formatted(appName));
        this.jwksUrl = environment.getProperty("%s.oauth.jwksUrl".formatted(appName));
    }
}

选项 2:注册自定义环境PostProcessor

通过为环境注册 PostProcess,您可以添加自己的动态值:

  1. 定义您的自定义属性源:
public class CustomPropertySource extends PropertySource<String> {

    private Environment environment;
    public CustomPropertySource(String name, Environment environment) {
        super(name); //name of the PropertySource, doesn't matter in our implementation
        this.environment = environment;
    }

    @Override
    public Object getProperty(String name) {
        if (name.equals("customUsername")) {
            // do similar magic with environment
            return "MY CUSTOM RUNTIME VALUE";
        }
        return null; // when no such value we return null
    }
}

  1. 定义您的环境后处理器:
class EnvironmentConfig implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment,
                                       SpringApplication application) {
        environment.getPropertySources()
                .addFirst(new CustomPropertySource("customPropertySource", environment));
    }
}

最后一步是你必须注册EnvironmentPostProcess,通过在src/main/resources/META-INF/spring.factories路径下创建spring.factories文件,并在其中添加以下行:

org.springframework.boot.env.EnvironmentPostProcessor=package.to.environment.config.EnvironmentConfig

选项 3:自定义
PropertySourcesPlaceholderConfigurer

负责解析这些占位符的类是一个名为 PropertySourcesPlaceholderConfigurer 的 BeanPostProcessor(请参阅此处)。

因此您可以覆盖它并提供我们的自定义 PropertySource 来解析该属性,如下所示:

@Component
public class CustomConfigurer extends PropertySourcesPlaceholderConfigurer {

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, ConfigurablePropertyResolver propertyResolver) throws BeansException {
        // again you would need to do some logic with environment bean to get your values and then set them as you wish
        ((ConfigurableEnvironment) beanFactoryToProcess.getBean("environment"))
                .getPropertySources()
                .addFirst(new CustomPropertySource("customPropertySource"));
        super.processProperties(beanFactoryToProcess, propertyResolver);
    }
}

最后一个选项可能需要设置

@Order
以确保它在设置其他值后运行。


总的来说,我推荐第一个选项,其他选项似乎不必要地复杂,但我只是想提供我所知道的所有选项。

© www.soinside.com 2019 - 2024. All rights reserved.