spring-boottomcatvirtual-threads

Spring Boot virtual threads on dedicated tomcat


We use our Spring Boot applications on dedicated tomcat servers, aka WAR deployment. I want to give virtual threads a try.

So for my understanding, using Java 21, tomcat11 and the latest Spring Boot (3.4.5) all i need to do is set spring.threads.virtual.enabled=true.

Is this sufficient?
How can I check, if virtual thread are used?

EDIT:
So basically we have kind of this scenario. A controller calls some IO service and returns the results like so:

@Controller
public String allUser(){
    return databaseService.fetchAllUser();
}

Without further configuration, is the call to fetchAllUser() called on a virtual thread?


Solution

  • No, if Spring Boot application is deployed as a WAR file under standalone Tomcat, a Controller method, which handles HTTP request, won't be executed with a virtual thread even if the Tomcat is running under Java 21 and spring.threads.virtual.enabled = true is specified in application.properties because in the case of standalone container the request gets handled by container's own thread pool.

    One of possible solutions for Tomcat 11 is to configure a Connector element in Tomcat server.xml file:

    <Connector 
            port="..." 
        protocol="HTTP/1.1" (or "org.apache.coyote.http11.Http11NioProtocol")
            useVirtualThreads="true">
    </Connector>
    

    It is always possible to check if current thread is virtual one with

    Thread.currentThread().isVirtual()
    

    SO thread Apache Tomcat with virtual thread discusses this issue in respect of older Tomcat versions and other Connector's protocols.

    Spring Boot: Difference between standalone application and WAR file deployment

    So, Spring Boot application, running as standalone Java app, and deployed as a WAR file differ, among other things, in just that - how Tomcat is configured.

    Spring Boot, running as a standalone application, configures its own, embedded, Tomcat and therefore has a full freedom to make it run the HTTP requests on any Executor of Spring Boot choice. When spring.threads.virtual.enabled = true is specified, Spring Boot configures the embedded Tomcat to handle HTTP request on virtual threads.

    In contrary, Spring Boot application, deployed as a WAR file to standalone/dedicated Tomcat instance, does not use its embedded Tomcat, and all Tomcat configuration burden is solely on that standalone/dedicated Tomcat, on which Spring Boot has no any influence.

    Another good question is: is spring.threads.virtual.enabled = true completely useless for Spring Boot application, deployed as a WAR file? Not necessarily. spring.threads.virtual.enabled = true configures not only the threads that handle HTTP requests for embedded servlet container, but host of other things: asynchronous methods (for example, annotated with @Async), @Scheduled methods, Batch engine and so on.

    On the practical side, even if allUser method will be handled by standalone/dedicated Tomcat which is configured with platform threads, method databaseService.fetchAllUser can still be run on virtual thread if this method is annotated with @Async and asynchrony is properly configured in Spring. allUser, as it is brought in the original post, won't benefit of such asynchrony, because one thread, Tomcat-managed, will be blocked while another one, Spring-managed, will be executed. It may make sense, however, if, for example, the actions in allUser can be parallelized into several calls, which then could be asynchronous; asynchronous HTTP request handling can be used and so on - this is design decision, heavily dependent on domain specific.