«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.