Spring WebFlux
Spring Boot 3.0 is based on the Spring Framework 6.0, which has built-in support for developing reactive applications. The Spring Framework uses Project Reactor as the base implementation of its reactive support and also comes with a new web framework, Spring WebFlux, which supports the development of reactive, that is, non-blocking, HTTP clients and services.
Spring WebFlux supports two different programming models:
- An annotation-based imperative style, similar to the already existing web framework, Spring Web MVC, but with support for reactive services
- A new function-oriented model based on routers and handlers
In this book, we will use the annotation-based imperative style to demonstrate how easy it is to move REST services from Spring Web MVC to Spring WebFlux and then start to refactor the services so that they become fully reactive.
Spring WebFlux also provides a fully reactive HTTP client, WebClient
, as a complement to the existing RestTemplate
client.
Spring WebFlux supports running on a servlet container based on the Jakarta Servlet specification v5.0 or higher, such as Apache Tomcat, but also supports reactive non-servlet-based embedded web servers such as Netty (https://netty.io/).
The Servlet specification is a specification in the Java EE platform that standardizes how to develop Java applications that communicate using web protocols such as HTTP.
Code examples of setting up a REST service
Before we can create a REST service based on Spring WebFlux, we need to add Spring WebFlux (and the dependencies that Spring WebFlux requires) to the classpath for Spring Boot to be detected and configured during startup. Spring Boot provides a large number of convenient starter dependencies that bring in a specific feature, together with the dependencies each feature normally requires. So, let’s use the starter dependency for Spring WebFlux and then see what a simple REST service looks like!
Starter dependencies
In this book, we will use Gradle as our build tool, so the Spring WebFlux starter dependency will be added to the build.gradle
file. It looks like this:
implementation('org.springframework.boot:spring-boot-starter-webflux')
You might be wondering why we don’t specify a version number. We will talk about that when we look at a complete example in Chapter 3, Creating a Set of Cooperating Microservices!
When the microservice is started up, Spring Boot will detect Spring WebFlux on the classpath and configure it, as well as other things such as starting up an embedded web server. Spring WebFlux uses Netty by default, which we can see from the log output:
2023-03-09 15:23:43.592 INFO 17429 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080
If we want to switch from Netty to Tomcat as our embedded web server, we can override the default configuration by excluding Netty from the starter dependency and adding the starter dependency for Tomcat:
implementation('org.springframework.boot:spring-boot-starter-webflux')
{
exclude group: 'org.springframework.boot', module: 'spring-boot-
starter-reactor-netty'
}
implementation('org.springframework.boot:spring-boot-starter-tomcat')
After restarting the microservice, we can see that Spring Boot picked Tomcat instead:
2023-03-09 18:23:44.182 INFO 17648 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
Property files
As you can see from the preceding examples, the web server is started up using port 8080
. If you want to change the port, you can override the default value using a property file. Spring Boot application property files can either be a .properties
file or a YAML file. By default, they are named application.properties
and application.yml
, respectively.
In this book, we will use YAML files so that the HTTP port used by the embedded web server can be changed to, for example, 7001
. By doing this, we can avoid port collisions with other microservices running on the same server. To do this, we can add the following line to the application.yml
file:
server.port: 7001
When we begin to develop our microservices as containers in Chapter 4, Deploying Our Microservices Using Docker, port collisions will no longer be a problem. Each container has its own hostname and port range, so all microservices can use, for example, port 8080
without colliding with each other.
Sample RestController
Now, with Spring WebFlux and an embedded web server of our choice in place, we can write a REST service in the same way as when using Spring MVC, that is, as a RestController
:
@RestController
public class MyRestService {
@GetMapping(value = "/my-resource", produces = "application/json")
List<Resource> listResources() {
…
}
The @GetMapping
annotation on the listResources()
method will map the Java method to an HTTP GET
API on the host:8080/myResource
URL. The return value of the List<Resource>
type will be converted into JSON.
Now that we’ve talked about Spring WebFlux, let’s see how we can document the APIs we develop using Spring WebFlux.