Spring Boot Reactive Tutorial
Let's make use of Spring 5's Reactive capabilities to make a simple Reactive, asynchronous web app using Spring Boot and other Spring tools.
Join the DZone community and get the full member experience.
Join For Free1. Overview
Spring 5, which will release later this year, will support building asynchronous and Reactive applications.
This is a simple tutorial showing the new features in Spring and how to create a web application. The application will connect to a database, have basic authentication, and be Reactive.
2. Reactive Programming
Reactive programming is about building asynchronous, non-blocking, and event-driven applications that can easily scale.
Each event is published to subscribers while ensuring that the subscribers are never overwhelmed.
Mono
and Flux
are implementations of the Publisher
interface. A Flux
will observe 0 to N items and eventually terminate successfully or not. A Mono
will observe 0 or 1 item, with Mono<Void>
hinting at most 0 items.
To learn more about Reactive Programming, you can refer to this article.
3. Dependencies
We'll use Gradle to build our project. I recommend using Spring Initializr for bootstrapping your project.
We'll use:
- Spring Boot 2
- Spring Webflux
- Spring Reactive Data MongoDB
- Spring Security Reactive Webflux
- Lombok
Not all the Spring libraries have a stable release yet.
Lombok is used to reduce boilerplate code for models and POJOs. It can generate setters/getters, default constructors, toString, etc. methods automatically.
buildscript {
ext {
springBootVersion = '2.0.0.M2'
}
...
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-mongodb-reactive')
compile('org.springframework.boot:spring-boot-starter-webflux')
compile('org.springframework.security:spring-security-core')
compile('org.springframework.security:spring-security-config')
compile('org.springframework.security:spring-security-webflux')
compileOnly('org.projectlombok:lombok')
...
}
4. Auto-Configuration
We'll leave Spring Boot to automatically configure our application based on the dependencies added.
@SpringBootApplication
@EnableReactiveMongoRepositories
@EnableWebFluxSecurity
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
For using non-default values in our application configuration, we can specify them as properties and Spring Boot will automatically use them to create beans.
spring.data.mongodb.database=demo
All beans necessary for MongoDB, Web, and Security will be automatically created.
5. Database
We'll be using MongoDB in our example and a simple POJO. A PersonRepository
bean will be created automatically.
@Data
@NoArgsConstructor
@Document
public class Person {
@Id
private String id;
private String name;
}
public interface PersonRespository extends ReactiveMongoRepository<Person, String> {
Flux<Person> findByName(String name);
}
6. Web API
We'll create REST endpoints for Person
.
Spring 5 added support for creating routes functionally while still supporting the traditional, annotation-based way of creating them.
Let's look at both of them with the help of examples.
6.1. Annotation-Based
This is the traditional way of creating endpoints.
@RestController
@RequestMapping("/person")
public class PersonController {
@Autowired
private PersonRespository personRespository;
@GetMapping
public Flux<Person> index() {
return personRespository.findAll();
}
}
This will create a REST endpoint, which will return all the Person
records reactively.
6.2. Router Functions
This is a new and concise way of creating endpoints.
@Bean
RouterFunction<?> routes(PersonRespository personRespository) {
return nest(path("/person"),
route(RequestPredicates.GET("/{id}"),
request -> ok().body(personRespository.findById(request.pathVariable("id")), Person.class))
.andRoute(method(HttpMethod.POST),
request -> {
personRespository.insert(request.bodyToMono(Person.class)).subscribe();
return ok().build();
})
);
}
The nest
method is used to create nested routes, where a group of routes share a common path (prefix), header, or other RequestPredicate
.
So, in our case, all the corresponding routes have the common prefix /person.
In the first route, we have exposed a GET API /person/{id}, which will retrieve the corresponding record and return it.
In the second route, we have exposed a POST API /person, which will receive a Person
object and save it in the DB.
The cURL commands for the same:
curl http://localhost:8080/person -v -u tom:password
curl http://localhost:8080/person/{id} -v -u tom:password
curl http://localhost:8080/person -X POST -d '{"name":"John Doe","age":20}' -H "Content-Type: application/json" -v -u tom:password
We should define the routes in a Spring configuration file.
7. Security
We'll be using a very simple basic authentication mechanism in our example.
@Bean
UserDetailsRepository userDetailsRepository() {
UserDetails tom = withUsername("tom").password("password").roles("USER").build();
UserDetails harry = withUsername("harry").password("password").roles("USER", "ADMIN").build();
return new MapUserDetailsRepository(tom, harry);
}
We have added some users for our application and assigned different roles to them.
8. Conclusion
I have tried explaining, with a simple example, how to build a simple Reactive web application using Spring Boot.
You can read more about:
You can find the complete example on GitHub.
Published at DZone with permission of Mohit Sinha, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments