Why reactive programming in Spring?
In Spring 5.0, spring added another parallel web-stack to the existing servlet based MVC web-stack. This new stack is fully reactive, non-blocking, and based on the project reactor library.
Now the question is why a new stack? Non-blocking code doesn't block any threads and hence it can scale with very few threads. This lets developers take advantage of multi-core, modern processors—handling huge numbers of concurrent requests. With this, you can satisfy more concurrent users with fewer microservice instances.
All the way reactive:
When we build reactive we need to make sure that we use all the libraries in the stack which are non-blocking. If code is doing any blocking operation anywhere in sequence then we will lose the advantage of using reactive stack. Sping has added various libraries to support this complete stack. We are going to use Spring Webflux and R2DBC here.
Building a Rest API using spring boot and PostgreSQL:
here, we are going to build a reactive REST (CRUD) API step-by-step, using the spring WebFlux and PostgreSQL database.
We will follow the below 4 steps:
- Create a Customer table in the local PostgreSQL database.
- Using Spring Initializer to build a base Spring Boot Project with required dependencies
- Import the project in IDE (I will be using IntelliJ IDEA) and setup database properties.
- Write a code:
- Write a model class.
- Write a spring repository interface.
- Write a Rest Controller and all CRUD operations
- Test the code using the rest client.
If you are more of a video person, you can check the video here or you can continue reading the blog:
Step 1: Setup a local database
I have PostgreSQL locally running, I will be connecting to it using SQL client and will run the following queries to create a customer table.
create table customer (id serial primary key, name text);
insert into customer(name) values("foo");
insert into customer(name) values("bar");
Step 2: Spring Initializer
Now the next step is to use a spring initializer to generate basic spring boot application code with required dependencies. Go to https://start.spring.io/ - and generate a project with the following dependencies.
- Spring Reactive Web - This will add reactive web-stack.
- Spring data R2DBC - Reactive relational database connectivity.
- PostgreSQL Driver - Since we want to connect the PostgreSQL database.
- Lombok - to reduce boilplate code (getter, setter, constructor etc.)
Step 3: Import the project folder into IDE like Intellij IDEA
Now, let's import the project into IDE, now if we try to run the SpringBootApplication class it will fail now. We need to add the following properties to the application.properties file to make it work. These will basically point to a locally running the postgreSQL database.
spring.r2dbc.url=r2dbc:postgresql://localhost/postgres
spring.r2dbc.username=postgres
spring.r2dbc.password=changeme
Step 4: Write the code.
The first step is to create a model class that matched the customer table we created in the database. we will create a class like below with Spring data annotation of @Table on class and @id and @Column for respective fields. we are also using Lombok annotation @Data which will automatically generate boilerplate( constructor, getter, setter, toString, hashcode, and equals) code for us.
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
@Table
@Data
public class Customer {
@Id
private Integer id;
@Column
private String name;
}
Now we need to create the ReactiveCrudRepository interface.
import com.example.reactivepostgresdemo.model.Customer;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface CustomerRepository extends ReactiveCrudRepository {
}
Once we have a repository we will use @RestController to create a controller class and inject the repository into it. Then we will implement all CRUD operations with @GetMapping @PostMapping @PutMapping and @DeleteMapping spring annotations.
import com.example.reactivepostgresdemo.model.Customer;
import com.example.reactivepostgresdemo.repo.CustomerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/customer")
public class CustomerController {
@Autowired
CustomerRepository repository;
@GetMapping
public Flux getCustomers(){
return repository.findAll();
}
@GetMapping("/{id}")
public Mono getCustomer(@PathVariable Integer id){
return repository.findById(id);
}
@PostMapping
public Mono createCustomer(@RequestBody Customer customer){
return repository.save(customer);
}
@PutMapping("/{id}")
public Mono updateCustomer(@RequestBody Customer customer, @PathVariable Integer id){
return repository.findById(id)
.map((c) -> {
c.setName(customer.getName());
return c;
}).flatMap( c -> repository.save(c));
}
@DeleteMapping("/{id}")
public Mono deleteCustomer(@PathVariable Integer id){
return repository.deleteById(id);
}
}



Comments
Post a Comment