Today we are going to learn about WebFlux. Why do you want to learn WebFlux all of a sudden?

Because I wanted to learn the Spring Cloud Gateway and found it was based on Technologies like Spring5.0+SpringBoot2.0+WebFlux. That’s why it’s important to take a quick look at WebFlux technology.

When IT came time to learn WebFlux, I found that I needed functional programming in Java 8, Stream streaming and other technologies as pre-knowledge. They go together like nesting dolls.

So there are two more articles to learn: lambda expressions and Java 8 streams.

I just want to learn the Spring Cloud Gateway, as a pre-knowledge, I do not plan to deeply study WebFlux for the time being, just a simple study.

With that said, let’s begin today’s lesson.

What is a WebFlux

The original Web Framework included in the Spring Framework, Spring Web MVC, was built specifically for the Servlet API and Servlet container. Spring WebFlux, the reactive stack Web framework, was added late in version 5.0. It is completely non-blocking, supports Reactive Stream backpressure, and runs on servers such as Netty, Undertow, and Servlet 3.1 + containers.

The above text and pictures are from the official website. From this we can roughly know that Spring WebFlux is benchmarking Spring MVC.

Spring WebFlux is an asynchronous non-blocking IO model that supports a large number of concurrent accesses with a small number of container threads. The underlying use of Netty containers also differs from traditional SpringMVC, which is servlet-based.

The response time of the interface will not be shortened due to the use of WebFlux, and the processing results of the server still have to be processed by the worker thread and then returned to the front end.

Reactive library

1. Reactive Stream

Reactive Stream is one of the terms you should notice. What does that mean?

Let’s start by looking at Reactive Programming, Microsoft’s approach to asynchronous Programming for server-side Programming in high-concurrency environments.

Reactive Stream is the specification for Reactive programming, and on the Java platform, Developed by Netflix (RxJava), TypeSafe (Scala, Akka), Pivatol (Spring, Reactor).

It consists of the following components:

  • Publisher: Publishes elements to subscribers
  • Subscriber: Consumption element
  • Subscribe: In a publisher, when a subscription is created, it is shared with the subscriber
  • Processor: Data is processed between publishers and subscribers

2. Reactor

Reactive Stream is a Reactive programming specification, but as an application API, applications will definitely need a higher-level, richer API to write asynchronous logic. That’s the role of the reaction library.

The Reactor framework is implemented by Pivotal based on Reactive Programming. It complies with the Reactive Streams specification. It provides Mono and Flux API types that handle 0.. 1 () and 0.. Data sequence of N (). Is a completely non-blocking, responsive programming framework for the JVM with efficient requirements management that handles “backpressure” well. Reactor is the preferred reaction library for Spring WebFlux.

From the above concepts, the most important thing to remember is Flux and Mono, the Reactor’s core classes:

  • Mono: Implements Publisher and returns 0 or 1 element.
  • Flux: Implements Publisher and returns N elements.

Both are publishers.

3. Reactive Stream, Reactor and WebFlux

Reactive Stream (Reactive Stream), Reactor (Reactor) and WebFlux (Reactive Stream)

  • Reactive StreamIt’s a set of reactive programmingstandard 和 specification;
  • ReactorIs based onReactive StreamsA set ofReactive programming framework;
  • WebFlux 以 ReactorBased on the implementationWebIn the field ofReactive programming framework.

Initial code experience

With all the concepts mentioned above, it’s finally time for the code section, so let’s briefly experience what the code looks like.

To create a Spring Boot project (Reactive Web), you need to build a Spring Boot project (Reactive Web). You need to build a Spring Boot project (Reactive Web).

1. Mono

@RestController
public class HelloController {
    @GetMapping("/hello")
    public Mono<String> hello(a) {
        long start = System.currentTimeMillis();
        Mono<String> hello = Mono.fromSupplier(() -> getHelloStr());
        System.out.println(Interface Time: + (System.currentTimeMillis() - start));
        return hello;
    }

    private String getHelloStr(a) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello"; }}Copy the code

To start the project, the browser accesses the /hello interface and the console outputs the following:

Interface time: 0

As you can see, in the WebFlux interface, requests are not blocked, so the interface time on the server side is 0.

2. Flux

@GetMapping(value = "/flux",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> flux(a) {
    Flux<String> flux = Flux.fromArray(new String[]{"Black"."Xiao pang".Small six ""."Xin"}).map(s -> {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Class two:" + s;
    });
    return flux;
}
Copy the code

The browser is as follows:

Flux is also a Publisher and can be produced by an array. Note that the content-type returned here is MediaType.TEXT_EVENT_STREAM_VALUE, text/event-stream.

Text /event-stream is a way for the server to push messages to the browser, which is a bit different from the WebSocket we are familiar with. I’m not going to write that for now.

Operating database

Spring Boot 2.3.0.release has officially supported the R2DBC based MySQL driver.

R2DBC: R2DBC is the Spring official in Spring5 released a responsive Web framework Spring WebFlux after the urgent need to meet the asynchronous response of the database interaction API, but due to the lack of standards and drivers, The Pivotal team began its own research on Reactive Relational Database Connectivity, The R2DBC specification API is proposed to evaluate the feasibility and discuss whether database vendors are interested in supporting responsive asynchronous non-blocking drivers. PostgreSQL, H2, and MSSQL were the first three vendors, but now MySQL has joined the fray.

Today we will learn how to operate MySQL database based on R2DBC.

1. Create projects

Select these dependencies and create a new project:

The pom.xml file looks like this:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-r2dbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>dev.miku</groupId>
        <artifactId>r2dbc-mysql</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>
Copy the code

And then the application. The properties:

server.port=8081
spring.r2dbc.url=r2dbcs:mysql://locahost:3306/test
spring.r2dbc.username=root
spring.r2dbc.password=root
Copy the code

2. Create a database table

CREATE TABLE `test_user`  (
  `user_id` int NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255),
  `age` int,
  `address` varchar(255),PRIMARY KEY (`user_id`) USING BTREE
) 
Copy the code

Create a simple test_user table.

3. Create related classes

Entity class

@Table("test_user")
public class User {
    @Id
    private int userId;
    private String userName;
    private int age;
    private String address;
    
    // omit the getter and setter
}
Copy the code

UserRepository, which is the DAO equivalent

public interface UserRepository extends ReactiveCrudRepository<User.Integer> {}Copy the code

UserController controller

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserRepository userRepository;

    @RequestMapping("/getAllUser")
    public Flux<User> getAllUser(a) {
        Flux<User> userFlux = userRepository.findAll();
        return userFlux;
    }

    @RequestMapping("/addUser")
    public Mono<User> addUser(User user) {
        Mono<User> mono = userRepository.save(user);
        returnmono; }}Copy the code

With that done, it’s time to launch the project and test it out.

4. Start the test

After the project started, we tested it with Postman.

Request address routing

We still use the database table and entity classes from the previous step, but instead of UserController, we use UserHandler and RouterConfiguration.

createUserhandler.java

@Component
public class UserHandler {

    @Autowired
    UserRepository userRepository;

    public Mono<ServerResponse> getAllUsers(ServerRequest serverRequest) {
        return ok().contentType(APPLICATION_JSON)
                .body(userRepository.findAll(), User.class);
    }

    public Mono<ServerResponse> addUser(ServerRequest serverRequest) {
        return ok().contentType(APPLICATION_JSON)
                .body(userRepository.saveAll(serverRequest.bodyToMono(User.class)), User.class);
    }

    public Mono<ServerResponse> deleteUser(ServerRequest serverRequest) {
        return userRepository.findById(Integer.valueOf(serverRequest.pathVariable("userId"))) .flatMap(user -> userRepository.delete(user).then(ok().build())) .switchIfEmpty(notFound().build()); }}Copy the code

createRouterConfiguration

@Configuration
public class RouterConfiguration {
    @Bean
    RouterFunction<ServerResponse> userRouterFunction(UserHandler userHandler) {
        return RouterFunctions.nest(RequestPredicates.path("/user"),
                RouterFunctions.route(RequestPredicates.GET("/getAllUser"), userHandler::getAllUsers)
                        .andRoute(RequestPredicates.POST("/addUser"), userHandler::addUser)
                        .andRoute(RequestPredicates.DELETE("/{userId}"), userHandler::deleteUser)); }}Copy the code
  1. This configuration class does something like thisSpringMVCIn theDispatcherServlet, responsible for the distribution of requests, according to different request URLS, find the corresponding processor to process.
  2. throughRouterFunctionsSuch a utility class to createRouterFunctionInstance.
  3. The nest method is called first, and the first parameter is set as a prefix to the address to be configured, similar to what we wrote directly on the Controller class@RequestMappingAnnotation to configure the address.
  4. nestThe second argument to the method isRouterFunctionExamples, every one of themRouterFunctionInstance byRouterFunctions.routeMethod, the first parameter is the requested URL (note that the address is configured with a common prefix), and the second parameter is configured with a method referenceHandlerFunctionThis is the handler of the current request.
  5. throughaddRouteMethod to configure multiple routing policies.

test

Modification:

The query is the same as before:

applicability

The website advises:

  • There is no need to migrate if you are using SpringMVC well. Imperative programming is the easiest way to write, understand, and debug code. Because the libraries and code of the old project were based on blocking.

  • If your team is going to use a non-blocking Web framework, WebFlux is certainly a technical route to consider, and it supports programming patterns in a way that is analogous to SpringMvc’s annotations. It is also possible to have WebMvc share controllers with WebFlux in a microservice architecture. The cost of switching is fairly small.

  • If you need to call a remote service in a SpringMVC project, you can consider using WebClient, and the return value of the method can be considered Reactive Type. The longer the latency of each call or the higher the interdependence of the calls, the greater the benefit.

  • In the microservices architecture, you can mix applications that use either Spring MVC or Spring WebFlux controller or Spring WebFlux functional endpoints. Supporting the same annotation-based programming model in both frameworks makes it easier to reuse knowledge while choosing the right tool for the right job.

Spring WebFlux is not about making your application run faster (compared to SpringMVC), it’s about scaling your system with limited resources, so it’s worth considering if you’re comfortable with responsive programming and applying it to your new system, otherwise stick with WebMVC.

conclusion

Learn here, more or less also have some understanding, but there are a lot of things to learn behind. Ok, so far I have added a lot of things, but it is still not perfect, I will add it later when I have time.

Article Reference:

Spring Reactor Programming (Juejin)

Initial experience of WebFlux (QQ.com)