Spring 中的 @ConditionalOnProperty 注解

1、概览

本文将带你了解 Spring 中 @ConditionalOnProperty 注解的作用和用法。

2、@ConditionalOnProperty 的作用

通常,在开发基于 Spring 的应用时,需要根据配置属性是否存在,或者配置属性有指定的值来有条件地创建一些 Bean。

例如,我们需要注册一个 DataSource Bean,并且要根据属性值设置为 prod 还是 test 来创建生产数据库或测试数据库。

这正是 @ConditionalOnProperty 注解的用武之地。

简而言之,@ConditionalOnProperty 只有在环境属性存在且具有指定值的情况下才会启用 Bean 注册。默认情况下,指定的属性必须已定义且等于指定的值。

熟悉了 @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 注解。

以这样一种方式配置 NotificationSender Bean:只有定义了 notification.service 属性,它才会被加载:

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

prefixname 属性用于表示应检查的配置属性。

最后,在 application.properties 文件中定义自定义属性:

notification.service=email

4、高级配置

如前所述,@ConditionalOnProperty 注解允许我们根据配置属性是否存在来有条件地注册 Bean。

@ConditionalOnProperty 注解能做的不仅于此。

假设我们想添加另一项通知服务,例如允许我们发送 SMS 通知的服务。

为此,创建另一个 NotificationSender 实现:

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

既然我们有了两种实现,那么来看看如何使用 @ConditionalOnProperty 来有条件地加载正确的 NotificationSender Bean。

为此,注解提供了 havingValue 属性。它定义了属性必须具有的值,以便将特定 Bean 添加到 Spring 容器中。

现在,指定在哪种情况下才在 Context 中注册 SmsNotification 实现:

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

havingValue 属性表示,只有当 notification.service 配置属性的值设置为 sms 时,才会加载 SmsNotification

@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 Bean。


Ref:https://www.baeldung.com/spring-conditionalonproperty