Generic Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

In this short tutorial, we're going to shed light on the main purpose of the @ConditionalOnProperty annotation.

First, we'll start with a bit of background about what @ConditionalOnProperty is. Then, we'll look at some practical examples to help understand how it works and what features it brings.

2. The Purpose of @ConditionalOnProperty

Typically, when developing Spring-based applications, we may need to create some beans conditionally based on the presence and the value of a configuration property.

For example, we may want to register a DataSource bean to point to a production or a test database depending on if we set a property value to “prod” or “test”.

Fortunately, achieving that isn't as hard as it might look upon first glance. The Spring framework provides the @ConditionalOnProperty annotation precisely for this purpose.

In short, the @ConditionalOnProperty enables bean registration only if an environment property is present and has a specific value. By default, the specified property must be defined and not equal to false.

Now that we're familiar with the purpose of the @ConditionalOnProperty annotation, let's dig deeper to see how it works.

3. The @ConditionalOnProperty Annotation in Practice

To exemplify the use of @ConditionalOnProperty, we'll develop a basic notification system. To keep things simple for now, let's assume that we want to send email notifications.

First, we'll need to create a simple service to send a notification message. For instance, consider the NotificationSender interface:

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

Next, let's provide an implementation of the NotificationSender interface to send our emails:

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

Now, let's see how to make use of the @ConditionalOnProperty annotation. Let's configure the NotificationSender bean in such a way that it will only be loaded if the property notification.service is defined:

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

As we can see, the prefix and name attributes are used to denote the configuration property that should be checked.

Finally, we need to add the last missing piece of the puzzle. Let's define our custom property in the application.properties file:

notification.service=email

4. Advanced Configuration

As we have already learned, the @ConditionalOnProperty annotation allows us to register beans conditionally depending on the presence of a configuration property.

However, we can do more than just that with this annotation. So, let's explore!

Let's suppose we want to add another notification service — for example, a service that will allow us to send SMS notifications.

To do that, we need to create another NotificationSender implementation:

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

Since we have two implementations, let's see how we can use @ConditionalOnProperty to load the right NotificationSender bean conditionally.

For this purpose, the annotation provides the havingValue attribute. Quite interestingly, it defines the value that a property must have in order for a specific bean to be added to the Spring container.

Now, let's specify under what condition we want to register the SmsNotification implementation in the context:

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

With the help of the havingValue attribute, we made it clear that we want to load SmsNotification only when notification.service is set to sms.

It's worth mentioning that @ConditionalOnProperty has another attribute called matchIfMissing. This attribute specifies whether the condition should match in case the property is not available.

Now, let's put all the pieces together and write a simple test case to confirm that everything works as expected:

@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. Conclusion

In this short tutorial, we highlighted the purpose of using the @ConditionalOnProperty annotation. Then, we showcased, through a practical example, how to use it to load Spring beans conditionally.

As always, the full source code of this tutorial is available over on GitHub.

Generic bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
1 Comment
Oldest
Newest
Inline Feedbacks
View all comments
Ravi Kumar
Ravi Kumar
2 months ago

Simply wow! Thanks for the good effort!

Comments are closed on this article!