Writing Reactive Repositories for Spring Data with Mongodb

Author: Shazin Sadakath


 

1. Overview

Reactive Programming has been alive for sometime now. Programming frameworks like Akka, Reactive Streams, Reactor, RxJava etc are good examples. In simple terms reactive programming is about writing non blocking software that are asynchronous and event driven.
Reactive Programming requires a small number of threads to scale vertically (Scale up inside a single JVM) instead of horizontally (Scale out to different nodes by means of clustering).
With Spring 5.0 there is out of the box support for Reactive Programming and now Spring Data project also has Reactive support. Now we will be looking at those latest features here in detail:

2. Setup

In order to use Spring Data Reactive Repositories we need to include spring-boot-starter-data-mongodb-reactive, de.flapdoodle.embed.mongo (for testing), rxjava and rxjava-reactive-streams. Plus reactive mongo-db driver is needed to make full use of the reactive capabilities. The maven dependencies will look like below:

        
            org.springframework.boot
            spring-boot-starter-data-mongodb-reactive
            2.0.0.M6
        

        
            io.reactivex.rxjava2
            rxjava
            2.1.1
        

        
            io.reactivex
            rxjava-reactive-streams
            1.2.0
        

        
            de.flapdoodle.embed
            de.flapdoodle.embed.mongo
            2.0.0
            runtime
        


Complete pom.xml file can be found at the Github repository listed at the conclusion section.

3. Enabling Spring Data Reactive Repositories for Mongodb

As the title suggests we will have a look the Spring Data Reactive Repositories with Mongodb. The new @EnableReactiveMongoRepositories is introduced to enable Reactive Repository support for Mongodb. The following configuration enables Spring Data Reactive Repositories for Mongodb:

@SpringBootApplication(exclude = {MongoAutoConfiguration.class, 
                                  MongoDataAutoConfiguration.class })
@EnableReactiveMongoRepositories
@AutoConfigureAfter(EmbeddedMongoAutoConfiguration.class)
public class ApplicationConfiguration 
  extends AbstractReactiveMongoConfiguration {

    private final Environment environment;

    public ApplicationConfiguration(Environment environment) {
        this.environment = environment;
    }

    @Bean
    public LoggingEventListener mongoEventListener() {
        return new LoggingEventListener();
    }

    @Override
    @Bean
    @DependsOn("embeddedMongoServer")
    public MongoClient reactiveMongoClient() {
        int port = environment.getProperty("local.mongo.port", Integer.class);
        return MongoClients.create(String.format("mongodb://localhost:%d", port));
    }

    @Override
    protected String getDatabaseName() {
        return "reactive";
    }
}

4. Reactive Repositories

Spring Data project uses the repositories programming model which is the most high-level abstraction to deal with data. They’re comprised of a set of CRUD methods defined in a Spring Data provided interface and domain-specific query methods.
Mainly by using an interface named CrudRepository which exposes methods like findOne, delete, save. With Reactive Programming support Spring Data project has now introduced two more interfaces named ReactiveCrudRepository and RxJava2CrudRepository (for RxJava project support)

A typical Spring Data Reactive Repository would look like below:

public interface ReactiveTaxiRepository 
  extends ReactiveCrudRepository {

     Flux findByNumber(String taxiNumber); 

     @Tailable
     Flux findWithTailableCursorBy();

}

And a RxJava2 version of the same Repository would look like below:
 

public interface RxJava2TaxiRepository 
  extends RxJava2CrudRepository { 

     Flowable findByNumber(String taxiNumber);

     @Tailable
     Flowable findWithTailableCursorBy();

}

Note that Spring 5.0 Reactor Project specific Flux is returned in ReactiveTaxiRepository and RxJava project specific Flowable is returned in RxJava2TaxiRepository.

These repositories are really identical to standard Spring Data Repositories except for the fact that now they can return and/or accept as parameters, reactive elements such as Flux, Mono and Flowable.  By default, reactive repositories use Project Reactor types but other reactive libraries can also be used such as RxJava2 as shown above.

5. Using Spring Data Reactive Repositories for Mongodb

When using the new Spring Data Reactive Repositories, We can use the full features of Reactive Programming provided by the entities Flux, Mono or Flowable (RxJava2).
And now we look at Reactor version would like below:
 

// Find by Number, Aggregate to a List, Block until finish
List myTaxis = taxiRepository
  .findByNumber("CAL-4259") 
  .collectList() 
  .block();

And now we look at the RxJava2 version:
 

// Find by Number, Aggregate to a List, Block until finish
List myTaxis = rxJava2TaxiRepository
  .findByNumber("CAL-4259")
  .toList()
  .blockingGet();

The above codes will find Taxis by Number CAL-4259 and collect that Flux stream or Flowable stream into a List and will block until the collection is finished.

6. Streaming Data with Tailable Cursor

Spring Data Reactive Repositories provide a way to Stream Data as it arrives into Mongodb with a @Tailable annotation, sort of like an Event Source system. Sticking to our example of Taxis, we can Subscribe to a Tailable Stream and while being subscribed, insert Taxi entities into Mongodb.
This will enable to see newly added Taxi entities coming into system in real time in a streaming manner until the subscription is disposed of. Simulating Taxis entering into a City in real time:

 

// Find All, Subscribe, Be Active until disposed or completed.
Disposable subscription = taxiRepository.findWithTailableCursorBy() 
  .doOnNext(System.out::println) 
  .doOnComplete(() -> System.out.println("Finished")) 
  .doOnTerminate(() -> System.out.println("Terminated")) 
  .subscribe();

Thread.sleep(1000);

taxiRepository.save(new Taxi(UUID.randomUUID().toString(), "ABC-1234", 4)).subscribe();
Thread.sleep(100);

taxiRepository.save(new Taxi(UUID.randomUUID().toString(), "XYZ-1234", 4)).subscribe();
Thread.sleep(1000);
subscription.dispose();

taxiRepository.save(new Taxi(UUID.randomUUID().toString(), "DEF-1234", 4)).subscribe();

7. Advantages

Compared to a Standard Spring Data Repository, A Reactive Repository provides all the features of Reactive Programming to Data Retrieval. Just by using Reactive Repositories, we can easily filter, process, aggregate data returned declaratively and use asynchronous capabilities provided out of the box in Reactive Programming.

8. Conclusion

Reactive Programming provides a lot of features such Functional, Declarative style of Coding which is being rapidly adopted by developers and enables to write scale-able, easy to understand code.
Now with Spring Data Reactive Repositories these features can be easily incorporated into the existing features of Spring Data project. The complete Source code for the project can be found at GitHub .



Tags: SpringDataReactive MongoDB
Views: 1381
Register for more exciting articles

Comments

Please login or register to post a comment.


There are currently no comments.