«1. Обзор

В этом коротком руководстве мы собираемся пролить свет на основную цель аннотации @ConditionalOnProperty.

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

2. Назначение @ConditionalOnProperty

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

Например, мы можем захотеть зарегистрировать bean-компонент DataSource, чтобы он указывал на производственную или тестовую базу данных, в зависимости от того, устанавливаем ли мы значение свойства «prod» или «test».

К счастью, добиться этого не так сложно, как может показаться на первый взгляд. Фреймворк Spring предоставляет аннотацию @ConditionalOnProperty именно для этой цели.

Короче говоря, @ConditionalOnProperty разрешает регистрацию компонента только в том случае, если свойство среды присутствует и имеет определенное значение. По умолчанию указанное свойство должно быть определено и не равно false.

Теперь, когда мы знакомы с назначением аннотации @ConditionalOnProperty, давайте копнем глубже, чтобы увидеть, как она работает.

3. Аннотация @ConditionalOnProperty на практике

Чтобы проиллюстрировать использование @ConditionalOnProperty, мы разработаем базовую систему уведомлений. Чтобы упростить задачу, давайте предположим, что мы хотим отправлять уведомления по электронной почте.

Во-первых, нам нужно создать простую службу для отправки уведомления. Например, рассмотрим интерфейс NotificationSender:

public interface NotificationSender {
    String send(String message);
}

Далее давайте обеспечим реализацию интерфейса NotificationSender для отправки наших электронных писем:

public class EmailNotification implements NotificationSender {
    @Override
    public String send(String message) {
        return "Email Notification: " + message;
    }
}

Теперь давайте посмотрим, как использовать аннотацию @ConditionalOnProperty. Давайте настроим bean-компонент NotificationSender таким образом, чтобы он загружался только в том случае, если определено свойство notification.service:

@Bean(name = "emailNotification")
@ConditionalOnProperty(prefix = "notification", name = "service")
public NotificationSender notificationSender() {
    return new EmailNotification();
}

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

Наконец, нам нужно добавить последнюю недостающую часть головоломки. Давайте определим наше пользовательское свойство в файле application.properties:

notification.service=email

4. Расширенная конфигурация

Как мы уже узнали, аннотация @ConditionalOnProperty позволяет нам регистрировать bean-компоненты условно в зависимости от наличия свойства конфигурации.

Однако с помощью этой аннотации мы можем сделать больше. Итак, давайте исследовать!

Предположим, мы хотим добавить еще один сервис уведомлений — например, сервис, который позволит нам отправлять SMS-уведомления.

Для этого нам нужно создать еще одну реализацию NotificationSender:

public class SmsNotification implements NotificationSender {
    @Override
    public String send(String message) {
        return "SMS Notification: " + message;
    }
}

Поскольку у нас есть две реализации, давайте посмотрим, как мы можем использовать @ConditionalOnProperty для условной загрузки правильного bean-компонента NotificationSender.

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

Теперь давайте укажем, при каком условии мы хотим зарегистрировать реализацию SmsNotification в контексте:

@Bean(name = "smsNotification")
@ConditionalOnProperty(prefix = "notification", name = "service", havingValue = "sms")
public NotificationSender notificationSender2() {
    return new SmsNotification();
}

С помощью атрибута haveValue мы дали понять, что хотим загружать SmsNotification только тогда, когда notification.service настроен на смс.

Стоит отметить, что @ConditionalOnProperty имеет еще один атрибут, который называется matchIfMissing. Этот атрибут указывает, должно ли условие соответствовать, если свойство недоступно.

Теперь давайте соберем все воедино и напишем простой тестовый пример, чтобы убедиться, что все работает так, как ожидалось:

@Test
public void whenValueSetToEmail_thenCreateEmailNotification() {
    this.contextRunner.withPropertyValues("notification.service=email")
        .withUserConfiguration(NotificationConfig.class)
        .run(context -> {
            assertThat(context).hasBean("emailNotification");
            NotificationSender notificationSender = context.getBean(EmailNotification.class);
            assertThat(notificationSender.send("Hello From Baeldung!")).isEqualTo("Email Notification: Hello From Baeldung!");
            assertThat(context).doesNotHaveBean("smsNotification");
        });
}

5. Заключение

В этом коротком руководстве мы подчеркнули цель использования @ Аннотация ConditionalOnProperty. Затем мы продемонстрировали на практическом примере, как использовать его для условной загрузки компонентов Spring.

Как всегда, полный исходный код этого руководства доступен на GitHub.