Partner – Microsoft – NPI (cat= Spring)
announcement - icon

Azure Spring Apps is a fully managed service from Microsoft (built in collaboration with VMware), focused on building and deploying Spring Boot applications on Azure Cloud without worrying about Kubernetes.

And, the Enterprise plan comes with some interesting features, such as commercial Spring runtime support, a 99.95% SLA and some deep discounts (up to 47%) when you are ready for production.

>> Learn more and deploy your first Spring Boot app to Azure.

You can also ask questions and leave feedback on the Azure Spring Apps GitHub page.

1. Introduction

In this quick tutorial, we’re going to look into a relatively new Spring Boot annotation called @ConditionalOnThreading.

We’ll discover what this annotation’s condition is and how to satisfy it in order to create the bean.

2. Conditional Annotations

Although we’ve already covered conditional annotations in Spring Boot, it’s worth very briefly recalling them again.

Conditional annotations provide a way to register a bean in BeanFactory only if various specific conditions are met. Developers define these conditions for each annotation individually by using the Condition interface.

Spring Boot comes with a bunch of pre-defined Conditional annotations for common use cases. The common examples are @ConditionalOnProperty, @ConditionalOnBean, and @ConditionalOnClass.

3. @ConditionalOnThreading Theory

@ConditionalOnThreading is just another pre-defined conditional annotation in Spring Boot. It was added in version 3.2, which was itself a release candidate at the time of the article’s creation. To get early access to this release candidate, we should use the dedicated Spring artifacts repo.

The @ConditionalOnThreading annotation allows the creation of a bean only if Spring is configured to use a specific type of threading internally. By type of threads, it means either the platform threads or virtual threads. To recall, since Java 21, we have had the ability to use virtual threads instead of platform ones.

So, to configure Spring to use virtual threads internally, we use a property named spring.threads.virtual.enabled. If this property is true and we’re running on Java 21 or higher, then @ConditionalOnThreading annotation would allow the creation of the bean.

4. Annotation Usage Sample

Let’s now try to write some examples to demonstrate the use cases of this annotation. Let’s assume we have two beans annotated with @ConditionalOnThreading:

@Configuration
static class CurrentConfig {

    @Bean
    @ConditionalOnThreading(Threading.PLATFORM)
    ThreadingType platformBean() {
        return ThreadingType.PLATFORM;
    }

    @Bean
    @ConditionalOnThreading(Threading.VIRTUAL)
    ThreadingType virtualBean() {
        return ThreadingType.VIRTUAL;
    }
}

enum ThreadingType {
    PLATFORM, VIRTUAL
}

So, with the ConditionalOnThreading annotation, we’ll have one of these two beans created: either the platformBean or virtualBean. Let’s now create some tests to check how this annotation works:

ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
  .withUserConfiguration(CurrentConfig.class);

@Test
@EnabledForJreRange(max = JRE.JAVA_20)
public void whenJava20AndVirtualThreadsDisabled_thenThreadingIsPlatform() {
    applicationContextRunner.withPropertyValues("spring.threads.virtual.enabled=false").run(context -> {
        Assertions.assertThat(context.getBean(ThreadingType.class)).isEqualTo(ThreadingType.PLATFORM);
    });
}

@Test
@EnabledForJreRange(min = JRE.JAVA_21)
public void whenJava21AndVirtualThreadsEnabled_thenThreadingIsVirtual() {
    applicationContextRunner.withPropertyValues("spring.threads.virtual.enabled=true").run(context -> {
        Assertions.assertThat(context.getBean(ThreadingType.class)).isEqualTo(ThreadingType.VIRTUAL);
    });
}

@Test
@EnabledForJreRange(min = JRE.JAVA_21)
public void whenJava21AndVirtualThreadsDisabled_thenThreadingIsPlatform() {
    applicationContextRunner.withPropertyValues("spring.threads.virtual.enabled=false").run(context -> {
        Assertions.assertThat(context.getBean(ThreadingType.class)).isEqualTo(ThreadingType.PLATFORM);
    });
}

Here, we have an ApplicationContextRunner instance that creates a lightweight application context for tests. We use it to set up the value of the spring property spring.threads.virtual.enabled. We’ve also annotated the tests with @EnabledForJreRange annotation. This annotation allows us to run tests only on certain Java versions.

As we can notice, for the ThreadingType bean to be Virtual, we must have the property set to true and at least Java 21. In other cases, the annotation condition is false.

5. Conclusion

In this short article, we’ve explored a new Spring annotation – @ConditionalOnThreading. It is available as a part of Spring Boot 3.2. This annotation allows the creation of the bean only if Spring is configured to use a special kind of threading internally via property.

As always, the source code for the article is available over on GitHub.

Course – LS (cat=Spring)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.