1. Inleiding
In deze zelfstudie gaan we zien hoe databasebewerkingen kunnen worden geconfigureerd en geïmplementeerd met behulp van Reactive Programming via Spring Data Reactive Repositories met MongoDB.
We bespreken het basisgebruik van ReactiveCrud Repository, ReactiveMongoRepository , evenals ReactiveMongoTemplate.
Hoewel deze implementaties reactieve programmering gebruiken, is dat niet de primaire focus van deze tutorial.
2. Omgeving
Om Reactive MongoDB te gebruiken, moeten we de afhankelijkheid toevoegen aan onze pom.xml.
We voegen ook een ingesloten MongoDB toe om te testen:
<dependencies>
// ...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3. Configuratie
Om de reactieve ondersteuning te activeren, moeten we de @EnableReactiveMongoRepositories gebruiken samen met wat infrastructuurconfiguratie:
@EnableReactiveMongoRepositories
public class MongoReactiveApplication
extends AbstractReactiveMongoConfiguration {
@Bean
public MongoClient mongoClient() {
return MongoClients.create();
}
@Override
protected String getDatabaseName() {
return "reactive";
}
}
Merk op dat het bovenstaande nodig zou zijn als we de zelfstandige MongoDB-installatie zouden gebruiken. Maar aangezien we Spring Boot gebruiken met geïntegreerde MongoDB in ons voorbeeld, is de bovenstaande configuratie niet nodig.
4. Een Document maken
Laten we voor de onderstaande voorbeelden een Account maken class en annoteer het met @Document om het te gebruiken in de databasebewerkingen:
@Document
public class Account {
@Id
private String id;
private String owner;
private Double value;
// getters and setters
}
5. Reactieve opslagplaatsen gebruiken
We zijn al bekend met het repositories-programmeermodel, met de CRUD-methoden die al zijn gedefinieerd, plus ondersteuning voor een aantal andere veelvoorkomende dingen.
Met het Reactive-model krijgen we nu dezelfde set methoden en specificaties, behalve dat we de resultaten en parameters op een reactieve manier behandelen.
5.1. ReactiveCrudRepository
We kunnen deze repository op dezelfde manier gebruiken als de blokkerende CrudRepository :
@Repository
public interface AccountCrudRepository
extends ReactiveCrudRepository<Account, String> {
Flux<Account> findAllByValue(String value);
Mono<Account> findFirstByOwner(Mono<String> owner);
}
We kunnen verschillende soorten argumenten doorgeven, zoals gewoon (String ), verpakt (Optioneel , Streamen ), of reactief (Mono , Flux ) zoals we kunnen zien in de findFirstByOwner() methode.
5.2. ReactiveMongoRepository
Er is ook de ReactiveMongoRepository interface, die erft van ReactiveCrudRepository en voegt enkele nieuwe zoekmethoden toe:
@Repository
public interface AccountReactiveRepository
extends ReactiveMongoRepository<Account, String> { }
De ReactiveMongoRepository gebruiken , we kunnen bijvoorbeeld vragen:
Flux<Account> accountFlux = repository
.findAll(Example.of(new Account(null, "owner", null)));
Als resultaat krijgen we elk account dat is hetzelfde als het doorgegeven voorbeeld.
Nu onze repositories zijn gemaakt, hebben ze al gedefinieerde methoden om sommige databasebewerkingen uit te voeren die we niet hoeven te implementeren:
Mono<Account> accountMono
= repository.save(new Account(null, "owner", 12.3));
Mono<Account> accountMono2 = repository
.findById("123456");
5.3. RxJava2CrudRepository
Met RxJava2CrudRepository, we hebben hetzelfde gedrag als de ReactiveCrudRepository, maar met de resultaten en parametertypes van RxJava :
@Repository
public interface AccountRxJavaRepository
extends RxJava2CrudRepository<Account, String> {
Observable<Account> findAllByValue(Double value);
Single<Account> findFirstByOwner(Single<String> owner);
}
5.4. Onze basisbewerkingen testen
Om onze repository-methoden te testen, gebruiken we de testabonnee:
@Test
public void givenValue_whenFindAllByValue_thenFindAccount() {
repository.save(new Account(null, "Bill", 12.3)).block();
Flux<Account> accountFlux = repository.findAllByValue(12.3);
StepVerifier
.create(accountFlux)
.assertNext(account -> {
assertEquals("Bill", account.getOwner());
assertEquals(Double.valueOf(12.3) , account.getValue());
assertNotNull(account.getId());
})
.expectComplete()
.verify();
}
@Test
public void givenOwner_whenFindFirstByOwner_thenFindAccount() {
repository.save(new Account(null, "Bill", 12.3)).block();
Mono<Account> accountMono = repository
.findFirstByOwner(Mono.just("Bill"));
StepVerifier
.create(accountMono)
.assertNext(account -> {
assertEquals("Bill", account.getOwner());
assertEquals(Double.valueOf(12.3) , account.getValue());
assertNotNull(account.getId());
})
.expectComplete()
.verify();
}
@Test
public void givenAccount_whenSave_thenSaveAccount() {
Mono<Account> accountMono = repository.save(new Account(null, "Bill", 12.3));
StepVerifier
.create(accountMono)
.assertNext(account -> assertNotNull(account.getId()))
.expectComplete()
.verify();
}
6. ReactiveMongoTemplate
Naast de repositories-aanpak hebben we deReactiveMongoTemplate .
Allereerst moeten we ReactiveMongoTemplate . registreren als boon:
@Configuration
public class ReactiveMongoConfig {
@Autowired
MongoClient mongoClient;
@Bean
public ReactiveMongoTemplate reactiveMongoTemplate() {
return new ReactiveMongoTemplate(mongoClient, "test");
}
}
En dan kunnen we deze boon in onze service injecteren om de databasebewerkingen uit te voeren:
@Service
public class AccountTemplateOperations {
@Autowired
ReactiveMongoTemplate template;
public Mono<Account> findById(String id) {
return template.findById(id, Account.class);
}
public Flux<Account> findAll() {
return template.findAll(Account.class);
}
public Mono<Account> save(Mono<Account> account) {
return template.save(account);
}
}
ReactiveMongoTemplate heeft ook een aantal methoden die niet gerelateerd zijn aan het domein dat we hebben, je kunt ze bekijken in de documentatie.