[spring-projects/spring-boot]ConfigurationPropertySources 已涵盖的源短路检查

2024-04-10 963 views
6

目前ConfigurationPropertySources已添加到环境中,以便轻松的属性解析可以直接工作。它ConfigurationPropertySources充当现有财产来源的门面。

当进行诸如 之类的调用时environment.getProperty("test"),如果找到该属性,ConfigurationPropertySources则将返回结果。但是,如果未找到该属性,则ConfigurationPropertySources继续PropertySourcesPropertyResolver检查所有后续来源。对于已经通过 进行检查的任何来源来说,这有点低效ConfigurationPropertySources


报告原文:

图像

getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders)inorg.springframework.core.env.PropertySourcesPropertyResolver遍历了 all PropertySources,那么为什么要使用ConfigurationPropertySourcesPropertySource来包装这些PropertySources集合,并且ConfigurationPropertySourcesPropertySource 也会被遍历呢?这样看来,ConfigurationPropertySourcesPropertySource已经遍历完之后,剩下的元素再遍历似乎没什么意义了,因为ConfigurationPropertySourcesPropertySource已经被检查过了

图像

回答

1

抱歉,我不明白你在报告什么。如果您认为您发现了错误,请提供一个显示问题的示例应用程序。

5

@philwebb我想知道为什么要ConfigurationPropertySources.attach(environment);在方法中调用方法SpringApplication.prepareEnvironment(...),它只包含PropertySource集合然后将其放入环境中。

所以调用时environment.getProperty("user.password")ConfigurationPropertySourcesPropertySource("configurationProperties")先查询,但如果在集合中找不到该属性值configurationProperties,则不会在集合的其余部分中查询,因为configurationProperties已经包含了下面的集合。

commandLineArgs
servletConfigInitParams
servletContextInitParams
systemProperties
systemEnvironment
random
applicationConfig: [classpath:/application.properties]

我只是想表达,因为ConfigurationPropertySources.attach(environment);被调用,导致遍历查找PropertySourcesPropertyResolver.getProperty(...)变得多余。所以我想知道为什么打电话ConfigurationPropertySources.attach(environment);

9

我已编辑您的评论以改进格式。您可能需要查看此Mastering Markdown 指南以供将来参考。

9

@brucelwl 问题跟踪器不是进行此类讨论的地方,因为它为每个订阅者增加了很多噪音。我们更愿意保留它以防止错误或功能请求。此类问题可以在 stackoverflow.com 或 gitter.im 上提出。

1

@philwebb我不只是问为什么,这也是一个逻辑错误,因为它导致冗余循环遍历

9

@brucelwl我不认为存在逻辑错误,但如果您可以提供一个示例来显示您的意思,我很乐意看一下。允许ConfigurationPropertySourcesPropertySource您使用标准环境访问 Spring Boot 属性。例如,您可以调用environment.getProperty("customer.someExample")它,它会customer.some-exampleapplication.propertiesCUSTOMER_SOMEEXAMPLE系统环境中查找。该类PropertySourcesPropertyResolver返回第一个非空结果。

8

请看一下我的demo, https://github.com/brucelwl/demo 代码很简单就是调用environment.getProperty("user.password"),但是你可能需要在PropertySourcesPropertyResolver.getProperty(...), 第81行添加一个断点。我们可以看到集合this.propertySources包含以下要素: configurationProperties commandLineArgs servletConfigInitParams servletContextInitParams systemProperties systemEnvironment random applicationConfig: [classpath:/application.properties]

但我们可以看到第一个PropertySourceconfigurationProperties还包含以下集合元素: commandLineArgs servletConfigInitParams servletContextInitParams systemProperties systemEnvironment random applicationConfig: [classpath:/application.properties]

使用循环从每个 propertySource 中查找键值对时,如果从第一个 PropertySource 中找不到configurationProperties,那么其余的 PropertySource 肯定也找不到,所以不需要继续查找

图像

4

@brucelwl 感谢您提供的示例,我明白您现在得到了什么。仅当找到该值时,才会短路后续属性源的检查。如果未找到该值,则我们再次搜索源。

不幸的是,修复这个问题并不容易。如果我们能够PropertySourcesPropertyResolver在 Spring 框架中进行更改,以某种方式意识到属性源也涵盖其他源,我们也许能够改进事情。

7

@philwebb我认为没有必要添加到ConfigurationPropertySourcesPropertySourceMutablePropertySources只需要成为ConfigurationPropertySources.this 的静态变量即可解决问题。当然,这只是我的建议。这是我的示例代码:

public class MyConfigurationPropertySources {

    private static final String ATTACHED_PROPERTY_SOURCE_NAME = "configurationProperties";

    private static ConfigurationPropertySourcesPropertySource configurationSources;

    private MyConfigurationPropertySources() {
    }

    public static boolean isAttachedConfigurationPropertySource(PropertySource<?> propertySource) {
        return ATTACHED_PROPERTY_SOURCE_NAME.equals(propertySource.getName());
    }

    public static void attach(Environment environment) {
        Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
        MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
        //PropertySource<?> attached = sources.get(ATTACHED_PROPERTY_SOURCE_NAME);
        //if (attached != null && attached.getSource() != sources) {
        //    sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
        //    attached = null;
        //}
        //if (attached == null) {
        //    sources.addFirst(new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
        //            new SpringConfigurationPropertySources(sources)));
        //}

        configurationSources = new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
                new SpringConfigurationPropertySources(sources));
    }

    public static Iterable<ConfigurationPropertySource> get(Environment environment) {
        Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
        MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
        //ConfigurationPropertySourcesPropertySource attached = (ConfigurationPropertySourcesPropertySource) sources
        //        .get(ATTACHED_PROPERTY_SOURCE_NAME);
        ConfigurationPropertySourcesPropertySource attached = configurationSources;
        if (attached == null) {
            return from(sources);
        }
        return attached.getSource();
    }

    public static Iterable<ConfigurationPropertySource> from(PropertySource<?> source) {
        return Collections.singleton(SpringConfigurationPropertySource.from(source));
    }

    public static Iterable<ConfigurationPropertySource> from(Iterable<PropertySource<?>> sources) {
        return new SpringConfigurationPropertySources(sources);
    }

    private static Stream<PropertySource<?>> streamPropertySources(PropertySources sources) {
        return sources.stream().flatMap(org.springframework.boot.context.properties.source.MyConfigurationPropertySources::flatten)
                .filter(org.springframework.boot.context.properties.source.MyConfigurationPropertySources::isIncluded);
    }

    private static Stream<PropertySource<?>> flatten(PropertySource<?> source) {
        if (source.getSource() instanceof ConfigurableEnvironment) {
            return streamPropertySources(((ConfigurableEnvironment) source.getSource()).getPropertySources());
        }
        return Stream.of(source);
    }

    private static boolean isIncluded(PropertySource<?> source) {
        return !(source instanceof PropertySource.StubPropertySource)
                && !(source instanceof ConfigurationPropertySourcesPropertySource);
    }
}
5

@brucelwl 一个 static 不起作用,因为应用程序可以有多个Environment.

5

@philwebb也许我们可以通过以下方式保存它Map<Environment,ConfigurationPropertySourcesPropertySource> configurationSources

public class MyConfigurationPropertySources {

    private static final String ATTACHED_PROPERTY_SOURCE_NAME = "configurationProperties";

    private static Map<Environment,ConfigurationPropertySourcesPropertySource> allEnvironmentSources`;

    private MyConfigurationPropertySources() {
    }
   .....
}
5

打扰一下,你修好了吗?

2

还没有。该问题仍然悬而未决,目前已分配给一般待办事项。

9

你好,有什么帮助吗?

6

最后用缓存解决了吗?

8

@dngzs 问题仍然悬而未决