How to use WebFlux with Spring Boot

How to use WebFlux with Spring Boot

With the increasing complexity of Internet applications, the traditional request-response model has been unable to meet the growing demand. Traditional web applications use Servlet containers to process requests in a synchronous blocking manner. Requests need to wait for the corresponding processing logic to complete before returning results. The disadvantage of this method is obvious, it will block the thread, resulting in a waste of resources, but also limit the concurrent processing capability of the application.

WebFlux is a new reactive programming model introduced in Spring Framework 5. Based on the Reactor library, it can provide an asynchronous and non-blocking way to process requests, thereby improving the performance and scalability of applications. In this article, we'll cover how to use WebFlux with Spring Boot.

insert image description here

What is WebFlux?

WebFlux is a new reactive programming model introduced in Spring Framework 5. It is based on the Reactor library and can provide an asynchronous and non-blocking way to process requests. WebFlux implements the Reactive Streams specification and can interact with other libraries that implement it, such as Reactor and RxJava.

Compared with traditional web applications, WebFlux can provide higher throughput and lower latency, while also improving the scalability and fault tolerance of applications. WebFlux also provides some useful features like Reactive Data Access, Reactive Web Security, Reactive Web Client, etc.

Using WebFlux in Spring Boot

Using WebFlux with Spring Boot is very simple. We just need to add the Spring Boot WebFlux Starter dependency. Spring Boot WebFlux Starter includes all the necessary dependencies to help us quickly build WebFlux applications.

First, we need to add the Spring Boot WebFlux Starter dependency to the project's pom.xml file:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

After adding the dependencies, we can start writing the WebFlux application. We need to create a controller class that can handle requests and return responses. In this article, we'll create a simple controller class that accepts a GET request and returns Hello World.

First, we need to create a HelloWorldController class, which should extend the AbstractController class. AbstractController is an abstract class that provides methods for handling requests and returning responses.

package com.example.demo;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import reactor.core.publisher.Mono;

@RestController
public class HelloWorldController extends AbstractController {
    
    

    @GetMapping("/")
    public Mono<ResponseEntity<String>> helloWorld() {
    
    
        return Mono.just(ResponseEntity.ok("Hello World"));
    }
}

In this example, we create a HelloWorldController class and define a helloWorld method in that class. The helloWorld method uses the @GetMapping annotation to indicate that it can handle GET requests and set the requested path to the root path "/".

The helloWorld method returns a Mono object that wraps a ResponseEntity object representing the status code, headers, and body of the response. In this example, we set the response's status code to 200, indicating a successful request, and the body to "Hello World".

We can mark the HelloWorldController class with the @RestController annotation to indicate that it is a controller class. The @RestController annotation is equivalent to a combination of @Controller and @ResponseBody annotations.

We've now finished writing our WebFlux application. We can start the application and visit http://localhost:8080/ and should see a "Hello World" response.

Routing and handler functions for WebFlux

In WebFlux, we can use two different ways to handle requests: routes and handler functions.

routing

Routing is a traditional way of mapping requests to corresponding handler methods. In WebFlux, we can use the RouterFunctions class to create routes. The RouterFunctions class provides a number of methods that help us create routing and handler methods.

We can define routing by creating a RouterFunction object. A RouterFunction object consists of multiple router functions, each of which can handle a specific request. We can use the RouterFunctions.route method to create router functions.

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

import reactor.core.publisher.Mono;

@Configuration
public class RouterConfiguration {
    
    
    
    @Bean
    public RouterFunction<ServerResponse> route() {
    
    
        return RouterFunctions.route()
                .GET("/", request -> ServerResponse.ok()
                        .contentType(MediaType.TEXT_PLAIN)
                        .body(Mono.just("Hello World"), String.class))
                .build();
    }
}

In this example, we create a RouterConfiguration class and define a route method in this class. The route method creates a RouterFunction object and adds a router function. The router function handles the request for the root path "/" using the GET method and returns a Mono object containing the "Hello World" string.

We can use the @Configuration annotation to mark the RouterConfiguration class, indicating that it is a configuration class. When the application starts, Spring Boot will automatically scan all configuration classes and load them.

handler function

Handler functions are another way of handling requests in WebFlux. A handler function is a set of functions that accept requests and return responses. In WebFlux, we can use the HandlerFunction interface to define handler functions.

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

import reactor.core.publisher.Mono;

@Configuration
public class HandlerConfiguration {
    
    
    
    @Bean
    public HandlerFunction<ServerResponse> helloWorld() {
    
    
        return request -> ServerResponse.ok()
                .contentType(MediaType.TEXT_PLAIN)
                .body(Mono.just("Hello World"), String.class);
    }
    
    @Bean
    public RouterFunction<ServerResponse> route() {
    
    
        return RouterFunctions.route()
                .GET("/", helloWorld())
                .build();
    }
}

In this example, we create a HandlerConfiguration class and define a helloWorld method in this class. The helloWorld method returns a HandlerFunction object that can handle the request and return a response. We also create a route method that creates a RouterFunction object and adds the helloWorld method as a router function.

We can use the @Configuration annotation to mark the HandlerConfiguration class, indicating that it is a configuration class. When the application starts, Spring Boot will automatically scan all configuration classes and load them.

WebFlux's asynchronous programming model

In WebFlux, we can use an asynchronous programming model to handle requests. The asynchronous programming model can provide higher concurrent processing capabilities and lower latency, and can also reduce resource waste.

In WebFlux, we can use Mono and Flux classes to handle asynchronous operations. Mono represents a reactive sequence containing a single element, and Flux represents a reactive sequence containing multiple elements.

Here's an example using Mono and Flux:

package com.example.demo;

import java.time.Duration;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
public class HelloWorldController {
    
    

    @GetMapping(value = "/hello", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> hello() {
    
    
        return Flux.just("Hello", "World")
                .delayElements(Duration.ofSeconds(1))
                .map(String::toUpperCase);
    }

    @GetMapping(value= "/hello/{name}", produces = MediaType.TEXT_PLAIN_VALUE)
    public Mono<String> hello(@PathVariable String name) {
    
    
        return Mono.just("Hello " + name);
    }
}

In this example, we create a HelloWorldController class and define two methods: hello and helloWithName. The hello method returns a Flux object representing a reactive sequence containing two elements "Hello" and "World". We use the delayElements method to simulate an asynchronous operation with 1 second between each element. We also convert each element in the sequence to uppercase using the map method.

The helloWithName method uses the @PathVariable annotation to get the parameters in the request path and returns a Mono object containing the string "Hello" and the parameter value.

In WebFlux, we can also use Mono and Flux to handle asynchronous operations such as database queries and external API calls. In this case, we can use reactive libraries such as Reactive MongoDB, Reactive Redis, WebClient, etc. to handle asynchronous operations.

Testing for WebFlux

In WebFlux, we can use the WebTestClient class to test our application. The WebTestClient class provides a set of methods that help us send requests and verify responses.

Here is an example using WebTestClient:

package com.example.demo;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;

@WebFluxTest
public class HelloWorldControllerTest {
    
    

    @Autowired
    private WebTestClient webTestClient;

    @Test
    public void testHelloWorld() {
    
    
        webTestClient.get().uri("/")
                .accept(MediaType.TEXT_PLAIN)
                .exchange()
                .expectStatus().isOk()
                .expectBody(String.class).isEqualTo("Hello World");
    }
}

In this example, we create a HelloWorldControllerTest class and inject a WebTestClient object. We also define a testHelloWorld method that uses the WebTestClient object to send a GET request and verifies that the response is correct.

In WebFlux, we can also use MockServer and MockMvc to test our application. MockServer is a mock HTTP server that helps us test the asynchronous requests and responses of our applications. MockMvc is a framework for simulating an MVC environment that helps us test an application's controllers and views.

Summarize

In this article, we covered how to use WebFlux with Spring Boot. WebFlux is a reactive programming model based on the Reactor library, which can provide an asynchronous and non-blocking way to process requests, thereby improving the performance and scalability of applications. We also covered WebFlux's routing and handler functions, asynchronous programming model, and testing methods. Hope this article helps you understand how to use WebFlux with Spring Boot.

Guess you like

Origin blog.csdn.net/2302_77835532/article/details/131392430