Spring Boot is the de facto standard for developing web applications using Java. This framework has a lot of capabilities so that it can minimize the boiler plate code. What it means to the developers is, it is very much possible to configure or extend a Spring Boot application in many ways. This is such a scenario where Spring Boot applications can use Virtual Threads instead of Native Threads for all of its operations. We do not have to rewrite the entire application to take advantage of Virtual Threads, but all you have to do is make some configurations in the Spring Boot application. This is what we are going to explain below.
Start with a Spring Boot application
Go to the spring initializer site and generate an empty spring project with Spring 3.1 and Maven as the build system. Use Java 17 and add spring dependencies and generate the project. Once this is done, we can set up the project in the IDE. In this article, the latest intellij IDEA Community edition is used.
Open the project and change the Java version to 21 in the pom.xml file and reload the Maven project. We need to change it to the JDK 21 explicitly, in order to use Virtual Threads.
Virtual Threads configuration for Spring Boot Application
To make use of Virtual Threads for all our requests, we need to add the following entry in the application.properties file:
spring.thread-executor=virtual
This entry tells the Spring Boot application to use Virtual Threads instead of Native Threads.
But we are testing for both Virtual and Platform threads. In that case, we need to make one more configuration in our Spring Boot application, based on the property configured, we can switch between Virtual Thread and Native threads. We can achieve this in the Spring Boot application using @ConditionalOnProperty annotation. This is cool!
What is @ConditionalOnProperty annotation?
Suppose, we need to create or inject some beans based on the presence of the value configured in the property file, we can use @ConditionalOnProperty annotation. In our application.properties file we have already added this property spring.thread-executor=virtual. If this value is present, then we are going to configure Virtual Threads in the application. This way, we can take control of the components that are used in the application. Let’s check the syntax for this annotation.
@ConditionalOnProperty(
value = "spring.thread-executor",
havingValue = "virtual"
)
This annotation takes two parameters. First one is the key that is defined in the application.properties. In this case, it is spring.thread-executor and the second parameter is the value that is associated with the key in the property file, which is virtual.
ThreadConfiguration Class
We need one more class to configure the Virtual Threads when the Spring Boot application is going to boot, so that it will make sure that for all operations it will use only Virtual Threads. It will not use Native Threads. How can we do this? We can achieve this by adding a @Configuration annotation to a class and inject Virtual Thread related beans. Let’s take a look at the code below:
@Configuration
@ConditionalOnProperty(
value = "spring.thread-executor",
havingValue = "virtual"
)
public class ThreadConfiguration {
@Bean
public AsyncTaskExecutor applicationTaskExecutor() {
return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
}
@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
return protocolHandler -> {
protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
};
}
}
In the above code, we are injecting an AsyncTaskExecutor bean which will use a VirtualThreadPerTaskExecutor object. There is one more bean to signal the tomcat server to use the Virtual Threads for all the executions. This is achieved by configuring the TomcatProtocolHandlerCustomizer bean. This configuration is enabled with the help of @Configuration annotation.
But one thing to note here is that, this configuration will come into effect only when the property spring.thread-executor is available in the application.properties file. This is achieved with the help of @ConditionalOnProperty annotation mentioned above.
Now, we are all set to go. With these changes, when we start the Spring Boot application, it will use Virtual Threads instead of Native Threads for all the process. Otherwise, it will use only Native Threads.
