1. Inledning
I den här handledningen ska vi se hur man konfigurerar och implementerar databasoperationer med hjälp av reaktiv programmering genom Spring Data Reactive Repositories med MongoDB.
Vi går igenom de grundläggande användningarna av ReactiveCrud Förråd, ReactiveMongoRepository , samt ReactiveMongoTemplate.
Även om dessa implementeringar använder reaktiv programmering, är det inte det primära fokus i denna handledning.
2. Miljö
För att kunna använda Reactive MongoDB måste vi lägga till beroendet till vår pom.xml.
Vi kommer också att lägga till en inbäddad MongoDB för testning:
<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. Konfiguration
För att aktivera det reaktiva stödet måste vi använda @EnableReactiveMongoRepositories tillsammans med vissa infrastrukturinställningar:
@EnableReactiveMongoRepositories
public class MongoReactiveApplication
extends AbstractReactiveMongoConfiguration {
@Bean
public MongoClient mongoClient() {
return MongoClients.create();
}
@Override
protected String getDatabaseName() {
return "reactive";
}
}
Observera att ovanstående skulle vara nödvändigt om vi använde den fristående MongoDB-installationen. Men eftersom vi använder Spring Boot med inbäddad MongoDB i vårt exempel är ovanstående konfiguration inte nödvändig.
4. Skapa ett dokument
För exemplen nedan, låt oss skapa ett konto klass och kommentera den med @Document för att använda den i databasoperationerna:
@Document
public class Account {
@Id
private String id;
private String owner;
private Double value;
// getters and setters
}
5. Använda Reactive Repositories
Vi är redan bekanta med programmeringsmodellen för repositories, med CRUD-metoderna redan definierade plus stöd för några andra vanliga saker också.
Nu med den reaktiva modellen får vi samma uppsättning metoder och specifikationer, förutom att vi kommer att hantera resultaten och parametrarna på ett reaktivt sätt.
5.1. ReactiveCrudRepository
Vi kan använda detta arkiv på samma sätt som det blockerande CrudRepository :
@Repository
public interface AccountCrudRepository
extends ReactiveCrudRepository<Account, String> {
Flux<Account> findAllByValue(String value);
Mono<Account> findFirstByOwner(Mono<String> owner);
}
Vi kan skicka olika typer av argument som vanligt (String ), inslagna (Valfritt , Ström ), eller reaktiv (Mono , Flöde ) som vi kan se i findFirstByOwner() metod.
5.2. ReactiveMongoRepository
Det finns också ReactiveMongoRepository gränssnitt, som ärver från ReactiveCrudRepository och lägger till några nya frågemetoder:
@Repository
public interface AccountReactiveRepository
extends ReactiveMongoRepository<Account, String> { }
Använda ReactiveMongoRepository , kan vi fråga med exempel:
Flux<Account> accountFlux = repository
.findAll(Example.of(new Account(null, "owner", null)));
Som ett resultat kommer vi att få alla konton det är samma som exemplet.
Med våra arkiv skapade har de redan definierade metoder för att utföra vissa databasoperationer som vi inte behöver implementera:
Mono<Account> accountMono
= repository.save(new Account(null, "owner", 12.3));
Mono<Account> accountMono2 = repository
.findById("123456");
5.3. RxJava2CrudRepository
Med RxJava2CrudRepository, vi har samma beteende som ReactiveCrudRepository, men med resultaten och parametertyperna från RxJava :
@Repository
public interface AccountRxJavaRepository
extends RxJava2CrudRepository<Account, String> {
Observable<Account> findAllByValue(Double value);
Single<Account> findFirstByOwner(Single<String> owner);
}
5.4. Testa våra grundläggande funktioner
För att testa våra förvarsmetoder använder vi testprenumeranten:
@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
Förutom repositories-metoden har viReactiveMongoTemplate .
Först och främst måste vi registrera ReactiveMongoTemplate som en böna:
@Configuration
public class ReactiveMongoConfig {
@Autowired
MongoClient mongoClient;
@Bean
public ReactiveMongoTemplate reactiveMongoTemplate() {
return new ReactiveMongoTemplate(mongoClient, "test");
}
}
Och sedan kan vi injicera denna böna i vår tjänst för att utföra databasoperationerna:
@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 har även ett antal metoder som inte relaterar till den domän vi har, du kan kolla upp dem i dokumentationen.