Средство разрешения Spring @ConfigurationProperties игнорирует внешние свойства - PullRequest
0 голосов
/ 28 января 2020

Я использую аннотацию @ImportResource({"classpath:property-sources.xml"}) для вывода пути к некоторым файлам конфигурации.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <util:properties id="externalProperties"
                     ignore-resource-not-found="true"
                     location="file:${dir.data}/foo.properties"
    />

    <context:property-placeholder ignore-unresolvable="true" properties-ref="externalProperties"/>
</beans>

Итак, в приложении я могу внедрить любое свойство из foo.properties, используя @Value. Довольно часто, да.

Однако, когда я пытаюсь использовать @ConfigurationProperties, чтобы сделать то же самое, Spring Boot полностью игнорирует любое свойство, имеющее значение в этом файле. Сначала я подумал, что что-то не так с конфигурацией, но если я добавлю точно такое же свойство в application.yml, это сработает. Сравните:

foo.properties (игнорируется @ConfigurationProperties resolver)

descriptions.foo.bar.baz = test

application.yml (успешно обработано @ConfigurationProperties resolver)

descriptions:
  foo:
    bar:
      baz: test

Не должно быть никакой разницы. Кроме того, в самом компоненте нет ничего особенного:

@ConfigurationProperties(prefix = "descriptions", ignoreUnknownFields = false)
public class Descriptions {

    private Map<String, String> foo = new HashMap<>();

    public Map<String, String> getFoo() {
        return foo;
    }

    public void setFoo(Map<String, String> foo) {
        this.foo = foo;
    }
}

Почему @Value всегда работает, а @ConfigurationProperties работает только для application.yml?

Ответы [ 4 ]

1 голос
/ 28 января 2020

В вашем файле XML вы загружаете файл свойств в объект Properties, который затем передается в дополнительно настроенный PropertySourcePlaceholderConfigurer. Вот что делает все это пространство имен волхвы c.

PropertySourcePlaceholderConfigurer будет использовать свойства для разрешения выражений значений в @Value или xml. Это НЕ добавит загруженные свойства к Environment. Environment - это то, что используется ConfigurationPropertiesBindingPostProcessor в Spring Boot. Это также происходит очень рано в процессе.

Вместо этого вам следует либо поместить @PropertySource в свой класс аннотаций @SpringBootApplication:

@PropertySource(value="file:${dir.data}/foo.properties", ignoreResourceNotFound=true)

, либо указать, какие дополнительные файлы конфигурации следует загрузить, используя свойство spring.config.additional-location.

--spring.config.additional-location=file:${dir.data}/foo.properties

С последним вам не нужно ничего менять, просто укажите, какие файлы загружать при запуске.

0 голосов
/ 28 января 2020
public class someclassname{
 @Value("${file.name}")
 private String fileName;

            FileInputStream fip = new FileInputStream(fileName);
            Properties properties = new Properties();
            properties.load(fip);
//read your file contents
}

Значение file.name можно установить в файле свойств:

file.name=yourpath
0 голосов
/ 28 января 2020

Файл foo.properties дает объект Properties, который содержит строку => отображение строки "description.foo.bar.baz" => "test" . Строка "description.foo.bar.baz" в общем случае не может быть преобразована в структуру, как вложенные Map<String,Object> s.

С другой стороны, application.yml дает точно такую ​​же структуру, которую ожидает приложение, вложенная Map<String,Object> с. Так что это работает из-за этого, и из-за стирания типа: во время выполнения jvm знает только, что void setFoo(Map foo) ожидает Map. Таким образом, приложение будет выдавать ClassCastException, как только foo.get("bar") будет использоваться в качестве String, поскольку фактическим значением будет Map.

0 голосов
/ 28 января 2020

PropertySource аннотация может использоваться для достижения того же.

@Component
@PropertySource("classpath:foo.properties")
public class TestProperties {

    @Value("${descriptions.foo.bar.baz}")
    private String descriptions;

    //getters and setters

}

ConfigurationProperties эквивалент

    import org.springframework.boot.context.properties.ConfigurationProperties;

    @Configuration
    @PropertySource("classpath:foo.properties")
    @ConfigurationProperties
    public class TestProperties {

        private String descriptions;

        //getters and setters

    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...