Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Spring Boot Reactive Tutorial

DZone's Guide to

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.

· Java Zone ·
Free Resource

Get the Edge with a Professional Java IDE. 30-day free trial.

1. 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.

Get the Java IDE that understands code & makes developing enjoyable. Level up your code with IntelliJ IDEA. Download the free trial.

Topics:
spring 5 ,spring reactive ,java ,web app ,tutorial ,spring boot 2 ,reactor core

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}