当前位置: 首页 > 知识库问答 >
问题:

Spring Boot:尝试使用EnvironmentPostProcessor重写Application.Properties

邹海荣
2023-03-14

因此,我尝试使用存储在Cosul中的键/值来覆盖Application.Properties中的值。我试了两件事。

1)使用Spring Cloud Consul config.https://Cloud.Spring.io/spring-cloud-consual/reference/html/#spring-cloud-consual-config

如果我的application.properties中没有定义相同的键,那么这就起作用了。如果它是在application.properties中定义的,则属性文件中的值将用于所有@value注释解析。这与我想要的相反。

2)由于上述方法不起作用,我继续创建一个自定义的EnvironmentPostProcessor。我首先尝试构建一个MapPropertySource,并使用Environment.getPropertySources().AddAfter(..)。结果与上面相同。然后我尝试遍历所有属性源,找到一个名称包含“ApplicationConfig:[classpath://application”的属性源,如果存在则设置属性值,或者添加一个新的属性值。此外,我将MapPropertySource添加到“ApplicationConfig:[classpath://application”属性源所在的EnumerableCompositePropertySource

无论采用哪种方法,结果总是一样的。如果该键存在于Application.Properties中,则使用该值。

什么给?我实际上是在重写属性源中的值,在后处理程序完成它的工作之前,我可以在调试器中看到这些值。application.properties值是如何到达@value注释的?

这是我当前的后处理程序

@Order(Ordered.LOWEST_PRECEDENCE)
public class ConsulPropertyPostProcessor implements EnvironmentPostProcessor {


    private static final String PROPERTY_SOURCE_NAME = "applicationConfigurationProperties";

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        PropertySource<?> system = environment.getPropertySources().get(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);

        ConsulKVService consulKVService = new ConsulKVServiceImpl().instantiateConsulKVServiceImpl((String)system.getProperty("CONSUL_HOST"), (String)system.getProperty("CONSUL_TOKEN"));
        Map<String, Object> map = consulKVService.getConsulKeysAndValuesByPrefix((String)system.getProperty("CONSUL_PREFIX"));


        addOrReplace(environment.getPropertySources(), map);
    }

    private void addOrReplace(MutablePropertySources propertySources, Map<String, Object> map) {
        MapPropertySource target = new MapPropertySource("applicationConfig: [consulKVs]", map);
        if (propertySources.contains(PROPERTY_SOURCE_NAME)) {
            PropertySource<?> applicationConfigurationPropertySources = propertySources.get(PROPERTY_SOURCE_NAME);

            for(EnumerableCompositePropertySource applicationPropertySource : (ArrayList<EnumerableCompositePropertySource>)applicationConfigurationPropertySources.getSource()){
                if(applicationPropertySource.getName() != null
                        && applicationPropertySource.getName().contains("applicationConfig: [profile=")) {

                    for(PropertySource singleApplicationPropertySource : applicationPropertySource.getSource()){
                        if(singleApplicationPropertySource.getName().contains("applicationConfig: [classpath:/application")){

                            for (String key : map.keySet()) {
                                if(map.get(key) != null) {
                                    if (singleApplicationPropertySource.containsProperty(key)) {
                                        ((Properties) singleApplicationPropertySource.getSource())
                                                .setProperty(key, (String) map.get(key));
                                    } else {
                                        ((Properties) singleApplicationPropertySource.getSource()).put(key, (String) map.get(key));
                                    }
                                }
                            }
                            break;
                        }
                    }

                    applicationPropertySource.add(target);

                    break;


                }
            }

        }

    }
}
@Log4j
public class ConsulProperties implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {

    static ConfigurableEnvironment configurableEnvironment;
    private static final String PROPERTY_SOURCE_NAME = "applicationConfigurationProperties";

    public static ConfigurableEnvironment getConfigurableEnvironment() {
        return configurableEnvironment;
    }

    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        log.info("Received ApplicationEnvironmentPreparedEvent...");
        ConfigurableEnvironment environment = event.getEnvironment();
        configurableEnvironment = environment;
        Properties props = new Properties();

        ConsulKVService consulKVService = new ConsulKVServiceImpl()
                .instantiateConsulKVServiceImpl((String) configurableEnvironment.getProperty("CONSUL_HOST"),
                        (String) configurableEnvironment.getProperty("CONSUL_TOKEN"));
        Map<String, Object> map = consulKVService.getConsulKeysAndValuesByPrefix((String) configurableEnvironment.getProperty("CONSUL_PREFIX"));
        while(map.values().remove(null));
        addOrReplace(environment.getPropertySources(), map);
    }


    private void addOrReplace(MutablePropertySources propertySources, Map<String, Object> map) {
        MapPropertySource target = new MapPropertySource("applicationConfig: [consulKVs]", map);
        if (propertySources.contains(PROPERTY_SOURCE_NAME)) {
            PropertySource<?> applicationConfigurationPropertySources = propertySources.get(PROPERTY_SOURCE_NAME);

            for(EnumerableCompositePropertySource applicationPropertySource : (ArrayList<EnumerableCompositePropertySource>)applicationConfigurationPropertySources.getSource()){
                if(applicationPropertySource.getName() != null
                        && applicationPropertySource.getName().contains("applicationConfig: [profile=")) {

                    for(PropertySource singleApplicationPropertySource : applicationPropertySource.getSource()){
                        if(singleApplicationPropertySource.getName().contains("applicationConfig: [classpath:/application")){

                            for (String key : map.keySet()) {
                                if (singleApplicationPropertySource.containsProperty(key)) {
                                    ((Properties) singleApplicationPropertySource.getSource())
                                            .setProperty(key, (String) map.get(key));
                                } else {
                                    ((Properties) singleApplicationPropertySource.getSource()).put(key,
                                            map.get(key));
                                }
                            }


                            applicationPropertySource.add(target);

                            Properties properties = new Properties();
                            properties.putAll(map);
                            propertySources.addLast(new PropertiesPropertySource("consulKVs", properties));

                            break;
                        }
                    }


                    break;


                }
            }
        }
    }
}

共有1个答案

支铭晨
2023-03-14

看起来您正在试图改变spring不是为之设计的约定。您提供的代码并不容易维护,它需要对Spring内部有深刻的了解。坦率地说,如果不进行调试,我无法判断如何实现您想要的,但我想到了另一种方法

您可以通过以下方式使用spring配置文件:

假设您在application.properties中有一个属性db.name=abc,在consul中有一个属性db.name=xyz,我假设您的目标是让spring解析db.name=xyz

在本例中,将db.name=abc移动到application-local.properties中,如果您想从本地文件中获得属性,则使用--spring.profiles.active=local启动应用程序,如果您想使用consult,则不使用此配置文件。

您甚至可以在EnvironmentPostProcessor中动态添加一个活动概要文件(您已经有了),但这只是EnvironmentPostProcessor中的一行代码。

 类似资料:
  • 这是我上周问的一个问题的更新版本。 我正试图使用SmbFileInputStream将我的Android连接到我的PC上, 但应用程序(在我的平板电脑上)中止,并出现以下错误消息: 我正在使用try/catch,但它不会触发任何异常。 适用的代码如下所示: 当我尝试获取文件列表时,SmbFile不会中止,但sfile.list会中止。 我在一个本地网络上,而不是一个域。 平板电脑可以用另一个应用程

  • 我试图找出使用VAVR的Try的惯用方法。我正在查看的用例必须执行以下步骤: -获取鞋的列表(调用可以引发选中的异常) -清理每个鞋(调用可以引发选中的异常) -还原每个鞋(调用可以引发选中的异常) -返回清理/还原的鞋的列表 这是我的示例玩具代码,其中processRequest方法购买n双鞋,清洗 我的问题是:如何简化这种逻辑?是否存在可以消除的方法调用?是否可以提高可读性?

  • 问题内容: 我一直在看代码,并且看到了尝试资源的机会。我以前使用过标准的try-catch语句,看起来它们在做同样的事情。所以我的问题是“ 尝试使用资源”与“尝试捕获 ”之间的区别是什么,哪个更好。 这是尝试使用资源: 问题答案: 尝试使用资源的重点是确保可靠地关闭资源。 当你不使用try-with-resources时,存在一个潜在的陷阱,称为异常屏蔽。当try块中的代码引发异常,而finall

  • 我正在应用程序中使用React Datepicker。默认情况下,我希望使用“内联”功能,以便在加载页面时始终显示日历。我是这样做到的: 我传递和属性从我的文件。 一切都很顺利。 接下来,我想让我的第二页使用相同的组件——因为这似乎是一件合乎逻辑的事情。但是,我希望日历仅在单击输入时触发。我将选择的日期传递到下一页,因此文本字段填充为。 我想给用户选择不同日期的选项,所以如果他们点击输入,日历就会

  • 我正在做一个程序的一部分(关于语音识别和遥控车),其中代码重复多次。出于好奇,我想将其转换为类似于(原谅;我不知道表达式的类型),然后以类似以下方式调用它:、和或类似于、和。 在Java中使用简单的lambda函数的正确语法是什么?(我应该把它的类型写下来,而不是说?) 如果您好奇的话,下面是代码块:

  • 问题内容: 当我尝试使用示例之一提取图像时,在运行时出现以下异常: 这是最后两行中发生异常的代码部分: 问题答案: 在您的lib目录中添加commons-logging-1.1.1.jar或jcl-over-slf4j-1.7.6.jar。