I made two apps with similar code on Spring Boot.
- Reactive Netty spring boot webflux r2dbc.
- Nonreactive Tomcat spring boot postgres.
reactive pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>reactive</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>reactive</name>
<description>reactive</description>
<properties>
<java.version>1.8</java.version>
<mapstruct.version>1.4.2.Final</mapstruct.version>
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
</properties>
<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-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
</project>
Spring boot entry point
@SpringBootApplication(exclude = {ReactiveSecurityAutoConfiguration.class})
@Configuration
@EnableR2dbcRepositories
public class ReactiveApplication {
public static void main(String[] args) {
SpringApplication.run(ReactiveApplication.class, args);
}
}
application.yml
server:
port : 8083
spring:
data:
r2dbc:
repositories:
enabled: true
r2dbc:
url: r2dbc:postgresql://localhost:5432/reactive
username: postgres
password: 12345
properties:
schema: bookshop
logging:
level:
org:
springframework:
r2dbc: DEBUG
Controller
package com.example.reactive.controller;
import com.example.reactive.entity.Book;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RequestMapping("/book")
public interface BookController {
@ResponseStatus(code = HttpStatus.OK)
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
Mono<Book> saveBook(@RequestBody Book book);
@ResponseStatus(code = HttpStatus.OK)
@GetMapping("/{id}")
Mono<Book> getBookById(@PathVariable Long id);
@ResponseStatus(code = HttpStatus.OK)
@GetMapping("/all")
Flux<Book> getAllBooks();
}
ControllerImpl
package com.example.reactive.controller.impl;
import com.example.reactive.controller.BookController;
import com.example.reactive.entity.Book;
import com.example.reactive.repository.BookRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequiredArgsConstructor
public class BookControllerImpl implements BookController {
private final BookRepository bookRepository;
@Override
public Mono<Book> saveBook(Book book) {
return bookRepository.save(book);
}
@Override
public Mono<Book> getBookById(Long id) {
return bookRepository.findById(id);
}
@Override
public Flux<Book> getAllBooks() {
return bookRepository.findAll();
}
}
Entity
package com.example.reactive.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Book {
@Id
private Long id;
private String name;
private String author;
private String text;
}
Repository
package com.example.reactive.repository;
import com.example.reactive.entity.Book;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface BookRepository extends ReactiveCrudRepository<Book, Long> {
}
If you need more information, feel free to write comments.
EDITED
After adding thread-pool parameters of min value 50 and max value 100, reactive app become faster. I don't use get All property to compare apps. For testing I have been using J-METER.200 threads 200 times
get 1 different string
Latency of response nonreactive app - middle 6 ms. Latency of response reactive app - middle 10 ms.
post 1 string Latency of response nonreactive app - middle 37 ms. Latency of response reactive app - middle 6 ms!!!!!!!!
Computer parameters Processor Intel® Core™ i 5-10400 CPU @ 2.90 GHz × 12. RAM 16,0 GB.