Spring Boot @ConditionalOnExpression Annotation Example

In this section we will learn about @ConditionalOnExpression Annotation.


The @ConditionalOnExpression annotation allows configurations based on the result of a SpEL expression. 

The @ConditionalOnExpression annotation may be used on any class annotated with @Configuration@Component@Service & @Repository or on methods annotated with @Bean.

1. Using @ConditionalOnExpression on @Bean method

To illustrate the use of @ConditionalOnExpression, we will develop a basic notification system. To keep things simple for now, let's assume we want to send email notifications and sms notifications.

Define our application custom configuration properties,

notification.enabled=true
notification.sms.enabled=true
notification.email.enabled=false
notification.twitter.enabled=true

Next, we'll need to create a simple service to send a notification. For example, consider the Notification Sender interface:

public interface NotificationService {

}

In this example, the SMSNotificationService and EmailNotificationService class is only loaded if a particular SpEL is enabled,

@Configuration
public class AppConfig {

@Bean
@ConditionalOnExpression("${notification.enabled:false} " +
"&& ${notification.sms.enabled:false}")
public NotificationService smsNotificationService()
{
return new SMSNotificationService();
}

@Bean
@ConditionalOnExpression("${notification.enabled:false} " +
"&& ${notification.email.enabled:false}")
public NotificationService emailNotificationService()
{
return new EmailNotificationService();
}
}

Here SMSNotificationService class will load because notification.enabled=true and notification.sms.enabled=true, but EmailNotificationService class will not load because notification.email.enabled=false

By appending :false to the properties we tell Spring to use false as a default value.


2. Using @ConditionalOnExpression on @Service class

Suppose we want to add another notification service – for example, a service that will allow us to send Twitter notifications.

To do this, we need to create another Notification Sender implementation:

@ConditionalOnExpression("${notification.enabled:false} " +
"&& ${notification.twitter.enabled:false}")
@Service
public class TwitterNotificationService implements NotificationService{

public TwitterNotificationService() {
System.out.println("Inside TwitterNotificationService Constructor");
}
}

Here TwitterNotificationService class will load because notification.enabled=true and notification.twitter.enabled=true

The following example creates a Spring Boot web application which uses @ConditionalOnExpression annotation.

Project Directory



pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>spring-boot-conditionalonexpression-annotation-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-conditionalonexpression-annotation-example</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>


application.properties

notification.enabled=true
notification.sms.enabled=true
notification.email.enabled=false
notification.twitter.enabled=
true


NotificationService.java

package com.knf.dev.demo.service;

public interface NotificationService {

}


EmailNotificationService.java

package com.knf.dev.demo.service;

public class EmailNotificationService implements NotificationService {

public EmailNotificationService() {
System.out.println("Inside EmailNotificationService Constructor");
}
}


SMSNotificationService.java

package com.knf.dev.demo.service;

public class SMSNotificationService implements NotificationService{

public SMSNotificationService() {
System.out.println("Inside SMSNotificationService Constructor");
}
}


AppConfig.java

package com.knf.dev.demo.config;

import com.knf.dev.demo.service.EmailNotificationService;
import com.knf.dev.demo.service.NotificationService;
import com.knf.dev.demo.service.SMSNotificationService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

@Bean
@ConditionalOnExpression("${notification.enabled:false} " +
"&& ${notification.sms.enabled:false}")
public NotificationService smsNotificationService()
{
return new SMSNotificationService();
}

@Bean
@ConditionalOnExpression("${notification.enabled:false} " +
"&& ${notification.email.enabled:false}")
public NotificationService emailNotificationService()
{
return new EmailNotificationService();
}

}


TwitterNotificationService.java

package com.knf.dev.demo.service;

import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;

@ConditionalOnExpression("${notification.enabled:false} " +
"&& ${notification.twitter.enabled:false}")
@Service
public class TwitterNotificationService implements NotificationService{

public TwitterNotificationService() {
System.out.println("Inside TwitterNotificationService Constructor");
}
}


Run the application - Application.java

package com.knf.dev.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {


public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(Application.class, args);

context.close();
}
}

Application is the entry point that sets up the Spring Boot application. The @SpringBootApplication annotation enables auto-configuration and component scanning. 

Let's run this Spring boot application from either IntelliJ IDEA IDE by right click - Run 'Application.main()'
Or you can use the below maven command to run:

mvn spring-boot:run

Console Output:
Inside TwitterNotificationService Constructor
Inside SMSNotificationService Constructor


Download Source Code

More related topics,

Spring Core Annotations

Spring Web Annotations

Spring Boot Annotations

Comments

Popular posts from this blog

Spring Boot OpenAI Integration: Step-by-Step Guide

Orchestration-Based Saga Architecture and Spring Boot Microservices Implementation Guide

Spring Boot 3 + Angular 15 + Material - Full Stack CRUD Application Example