«1. Обзор

В этом руководстве показано, как настроить и использовать свойства в Spring с помощью конфигурации Java и @PropertySource.

Мы также увидим, как свойства работают в Spring Boot.

2. Регистрация файла свойств с помощью аннотаций

Spring 3.1 также представляет новую аннотацию @PropertySource как удобный механизм добавления источников свойств в среду.

Мы можем использовать эту аннотацию в сочетании с аннотацией @Configuration:

@Configuration
@PropertySource("classpath:foo.properties")
public class PropertiesWithJavaConfig {
    //...
}

Еще один очень полезный способ зарегистрировать новый файл свойств — использовать заполнитель, который позволяет нам динамически выбирать нужный файл во время выполнения: ~ ~~

@PropertySource({ 
  "classpath:persistence-${envTarget:mysql}.properties"
})
...

2.1. Определение нескольких местоположений свойств

Аннотация @PropertySource повторяется в соответствии с соглашениями Java 8. Поэтому, если мы используем Java 8 или выше, мы можем использовать эту аннотацию для определения нескольких местоположений свойств:

@PropertySource("classpath:foo.properties")
@PropertySource("classpath:bar.properties")
public class PropertiesWithJavaConfig {
    //...
}

Конечно, мы также можем использовать аннотацию @PropertySources и указать массив @PropertySource. Это работает в любой поддерживаемой версии Java, а не только в Java 8 или более поздней версии:

@PropertySources({
    @PropertySource("classpath:foo.properties"),
    @PropertySource("classpath:bar.properties")
})
public class PropertiesWithJavaConfig {
    //...
}

В любом случае стоит отметить, что в случае конфликта имени свойства последнее чтение исходного кода имеет приоритет.

3. Использование/внедрение свойств

Внедрить свойство с аннотацией @Value очень просто:

@Value( "${jdbc.url}" )
private String jdbcUrl;

Мы также можем указать значение по умолчанию для свойства:

@Value( "${jdbc.url:aDefaultUrl}" )
private String jdbcUrl;

Добавлен новый PropertySourcesPlaceholderConfigurer в Spring 3.1 разрешаются заполнители ${…} в значениях свойств определения компонента и аннотациях @Value.

Наконец, мы можем получить значение свойства с помощью Environment API:

@Autowired
private Environment env;
...
dataSource.setUrl(env.getProperty("jdbc.url"));

4. Свойства с Spring Boot

Прежде чем мы перейдем к более продвинутым параметрам настройки свойств, давайте потратим некоторое время на изучение поддержка новых свойств в Spring Boot.

Вообще говоря, эта новая поддержка требует меньше настроек по сравнению со стандартным Spring, что, конечно же, является одной из основных целей Boot.

4.1. application.properties: файл свойств по умолчанию

Boot применяет свой типичный подход к настройке файлов свойств. Это означает, что мы можем просто поместить файл application.properties в наш каталог src/main/resources, и он будет обнаружен автоматически. Затем мы можем внедрить из него любые загруженные свойства, как обычно.

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

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

java -jar app.jar --spring.config.location=classpath:/another-location.properties

Начиная с Spring Boot 2.3, мы также можем указать расположение подстановочных знаков для файлов конфигурации.

Например, мы можем установить для свойства spring.config.location значение config/*/:

java -jar app.jar --spring.config.location=config/*/

Таким образом, Spring Boot будет искать файлы конфигурации, соответствующие шаблону каталога config/*/, за пределами нашего jar-файла. файл. Это удобно, когда у нас есть несколько источников свойств конфигурации.

Начиная с версии 2.4.0, Spring Boot поддерживает использование файлов свойств, состоящих из нескольких документов, подобно тому, как это делает YAML: #).

baeldung.customProperty=defaultValue
#---
baeldung.customProperty=overriddenValue

4.2. Файл свойств среды

Если нам нужно ориентироваться на разные среды, для этого есть встроенный механизм в Boot.

Мы можем просто определить файл application-environment.properties в каталоге src/main/resources, а затем установить профиль Spring с тем же именем среды.

Например, если мы определяем «промежуточную» среду, это означает, что нам нужно определить промежуточный профиль, а затем application-staging.properties.

Этот файл env будет загружен и будет иметь приоритет над файлом свойств по умолчанию. Обратите внимание, что файл по умолчанию все равно будет загружен, просто в случае конфликта свойств приоритет имеет файл свойств, специфичный для среды.

4.3. Файл свойств, специфичных для теста

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

«Spring Boot обрабатывает это за нас, просматривая наш каталог src/test/resources во время тестового запуска. Опять же, свойства по умолчанию по-прежнему будут вводиться как обычно, но будут переопределены ими в случае коллизии.

4.4. Аннотация @TestPropertySource

Если нам нужен более детальный контроль над тестовыми свойствами, мы можем использовать аннотацию @TestPropertySource.

Это позволяет нам устанавливать свойства теста для определенного контекста теста, имея приоритет над источниками свойств по умолчанию:

Если мы не хотим использовать файл, мы можем указать имена и значения напрямую: ~ ~~

@RunWith(SpringRunner.class)
@TestPropertySource("/foo.properties")
public class FilePropertyInjectionUnitTest {

    @Value("${foo}")
    private String foo;

    @Test
    public void whenFilePropertyProvided_thenProperlyInjected() {
        assertThat(foo).isEqualTo("bar");
    }
}

Мы также можем добиться аналогичного эффекта, используя аргумент свойств аннотации @SpringBootTest:

@RunWith(SpringRunner.class)
@TestPropertySource(properties = {"foo=bar"})
public class PropertyInjectionUnitTest {

    @Value("${foo}")
    private String foo;

    @Test
    public void whenPropertyProvided_thenProperlyInjected() {
        assertThat(foo).isEqualTo("bar");
    }
}

4.5. Иерархические свойства

@RunWith(SpringRunner.class)
@SpringBootTest(
  properties = {"foo=bar"}, classes = SpringBootPropertiesTestApplication.class)
public class SpringBootPropertyInjectionIntegrationTest {

    @Value("${foo}")
    private String foo;

    @Test
    public void whenSpringBootPropertyProvided_thenProperlyInjected() {
        assertThat(foo).isEqualTo("bar");
    }
}

Если у нас есть свойства, сгруппированные вместе, мы можем использовать аннотацию @ConfigurationProperties, которая будет отображать эти иерархии свойств в графы объектов Java.

Давайте возьмем некоторые свойства, используемые для настройки соединения с базой данных:

А затем давайте воспользуемся аннотацией, чтобы сопоставить их с объектом базы данных:

database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar

Spring Boot снова применяет соглашение по сравнению с подходом к настройке, автоматическое сопоставление между именами свойств и их соответствующими полями. Все, что нам нужно предоставить, это префикс свойства.

@ConfigurationProperties(prefix = "database")
public class Database {
    String url;
    String username;
    String password;

    // standard getters and setters
}

Если вы хотите углубиться в свойства конфигурации, ознакомьтесь с нашей подробной статьей.

4.6. Альтернатива: файлы YAML

Spring также поддерживает файлы YAML.

Все те же правила именования применяются к файлам свойств, специфичным для теста, среды и файлам свойств по умолчанию. Единственная разница заключается в расширении файла и зависимости от библиотеки SnakeYAML, находящейся в нашем пути к классам.

YAML особенно хорош для иерархического хранения свойств; следующий файл свойств:

является синонимом следующего файла YAML:

database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar
secret: foo

Также стоит отметить, что файлы YAML не поддерживают аннотацию @PropertySource, поэтому, если нам нужно использовать эту аннотацию, она ограничит нас использованием файла свойств.

database:
  url: jdbc:postgresql:/localhost:5432/instance
  username: foo
  password: bar
secret: foo

Еще одним примечательным моментом является то, что в версии 2.4.0 Spring Boot изменил способ загрузки свойств из многодокументных файлов YAML. Ранее порядок их добавления основывался на порядке активации профиля. Однако в новой версии фреймворк следует тем же правилам упорядочения, которые мы указывали ранее для файлов .properties; свойства, объявленные ниже в файле, просто переопределяют те, что выше.

Кроме того, в этой версии профили больше нельзя активировать из документов, относящихся к профилю, что делает результат более ясным и предсказуемым.

4.7. Импорт дополнительных файлов конфигурации

До версии 2.4.0 Spring Boot позволял включать дополнительные файлы конфигурации с помощью свойств spring.config.location и spring.config.additional-location, но они имели определенные ограничения. Например, их нужно было определить перед запуском приложения (в качестве свойств среды или системы или с помощью аргументов командной строки), поскольку они использовались в начале процесса.

В упомянутой версии мы можем использовать свойство spring.config.import в файле application.properties или application.yml, чтобы легко включать дополнительные файлы. Это свойство поддерживает некоторые интересные функции:

добавление нескольких файлов или каталогов, файлы могут быть загружены либо из пути к классам, либо из внешнего каталога, указывающего, должен ли процесс запуска завершиться неудачно, если файл не найден, или если это необязательный импорт файла. файлы без расширений

    Давайте посмотрим на правильный пример:

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

spring.config.import=classpath:additional-application.properties,
  classpath:additional-application[.yml],
  optional:file:./external.properties,
  classpath:additional-application-properties/

Spring будет рассматривать импорт как новый документ, вставленный сразу после декларации импорта.

4.8. Свойства из аргументов командной строки

Помимо использования файлов, мы можем передавать свойства непосредственно в командной строке:

Мы также можем сделать это через системные свойства, которые предоставляются перед командой -jar, а не после нее:

java -jar app.jar --property="value"

4.9. Свойства переменных среды

java -Dproperty.name="value" -jar app.jar

«Spring Boot также обнаружит переменные среды, рассматривая их как свойства:

4.10. Рандомизация значений свойств

export name=value
java -jar app.jar

Если нам не нужны детерминированные значения свойств, мы можем использовать RandomValuePropertySource для рандомизации значений свойств:

4.11. Дополнительные типы источников свойств

random.number=${random.int}
random.long=${random.long}
random.uuid=${random.uuid}

Spring Boot поддерживает множество источников свойств, реализуя хорошо продуманный порядок, обеспечивающий разумное переопределение. Стоит ознакомиться с официальной документацией, которая выходит за рамки этой статьи.

5. Конфигурация с использованием необработанных компонентов — PropertySourcesPlaceholderConfigurer

Помимо удобных методов получения свойств в Spring, мы также можем определить и зарегистрировать компонент конфигурации свойств вручную.

Работа с PropertySourcesPlaceholderConfigurer дает нам полный контроль над конфигурацией, но недостаток в том, что он более подробный и в большинстве случаев ненужный.

Давайте посмотрим, как мы можем определить этот bean-компонент, используя конфигурацию Java:

6. Свойства в контекстах «родитель-потомок»

@Bean
public static PropertySourcesPlaceholderConfigurer properties(){
    PropertySourcesPlaceholderConfigurer pspc
      = new PropertySourcesPlaceholderConfigurer();
    Resource[] resources = new ClassPathResource[ ]
      { new ClassPathResource( "foo.properties" ) };
    pspc.setLocations( resources );
    pspc.setIgnoreUnresolvablePlaceholders( true );
    return pspc;
}

Этот вопрос возникает снова и снова: что происходит, когда наше веб-приложение имеет родителя и дочерний контекст? Родительский контекст может иметь некоторую общую базовую функциональность и bean-компоненты, а затем один (или несколько) дочерних контекстов, возможно, содержащих специфичные для сервлета bean-компоненты.

В таком случае, как лучше всего определить файлы свойств и включить их в эти контексты? И как лучше всего получить эти свойства из Spring?

Мы дадим простую разбивку.

Если файл определен в родительском контексте:

@Value работает в дочернем контексте: YES

    @Value работает в родительском контексте: YES
    environment.getProperty в дочернем контексте: YES
    environment .getProperty в родительском контексте: ДА
    Если файл определен в дочернем контексте:

@Value работает в дочернем контексте: ДА

    @Value работает в родительском контексте: НЕТ
    environment.getProperty в дочернем контекст: YES
    environment.getProperty в родительском контексте: NO
    7. Заключение

В этой статье показано несколько примеров работы со свойствами и файлами свойств в Spring.

Как всегда, весь код статьи доступен на GitHub.

«