Spring Webflux and @Cacheable Annotation

This commit is contained in:
Mladen Savic 2021-11-08 17:06:17 +01:00
parent 3ab032d095
commit 19437f2e13
8 changed files with 283 additions and 0 deletions

View File

@ -7,6 +7,9 @@
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId> <artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version> <version>1.0.0-SNAPSHOT</version>
<modules>
<module>spring-webflux-caching</module>
</modules>
<name>parent-modules</name> <name>parent-modules</name>
<packaging>pom</packaging> <packaging>pom</packaging>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.spring</groupId>
<artifactId>spring-webflux-caching</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>spring-webflux-caching</name>
<packaging>jar</packaging>
<description>Spring WebFlux Caching Sample</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<version>2.2.19</version>
</dependency>
<dependency>
<groupId>io.projectreactor.addons</groupId>
<artifactId>reactor-extra</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mongodb</artifactId>
<version>1.16.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,50 @@
package com.baeldung.caching;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class Item {
@Id
private String _id;
private String name;
private double price;
public Item(String name, double price) {
this.name = name;
this.price = price;
}
public Item() {
}
public String get_id() {
return _id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Item{" +
"id='" + _id + '\'' +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}

View File

@ -0,0 +1,8 @@
package com.baeldung.caching;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ItemRepository extends ReactiveMongoRepository<Item, String> {
}

View File

@ -0,0 +1,42 @@
package com.baeldung.caching;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import reactor.cache.CacheMono;
import reactor.core.publisher.Mono;
@Service
public class ItemService {
private final ItemRepository repository;
private final LoadingCache<String, Object> cache;
public ItemService(ItemRepository repository) {
this.repository = repository;
this.cache = Caffeine.newBuilder()
.build(this::getItem_withAddons);
}
@Cacheable("items")
public Mono<Item> getItem(String id) {
return repository.findById(id);
}
public Mono<Item> save(Item item) {
return repository.save(item);
}
@Cacheable("items")
public Mono<Item> getItem_withCache(String id) {
return repository.findById(id).cache();
}
@Cacheable("items")
public Mono<Item> getItem_withAddons(String id) {
return CacheMono.lookup(cache.asMap(), id)
.onCacheMissResume(() -> repository.findById(id).cast(Object.class)).cast(Item.class);
}
}

View File

@ -0,0 +1,16 @@
package com.baeldung.caching;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
@SpringBootApplication
@EnableMongoRepositories
@EnableCaching
public class SpringWebfluxCachingApplication {
public static void main(String[] args) {
SpringApplication.run(SpringWebfluxCachingApplication.class, args);
}
}

View File

@ -0,0 +1,2 @@
logging.level.org.springframework.data.mongodb.core.ReactiveMongoTemplate=DEBUG
logging.level.org.springframework.cache=TRACE

View File

@ -0,0 +1,95 @@
package com.baeldung.caching;
import org.assertj.core.api.Assertions;
import org.junit.ClassRule;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.utility.DockerImageName;
import reactor.core.publisher.Mono;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
public class MonoFluxResultCachingLiveTest {
@Autowired
ItemService itemService;
final static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"));
@DynamicPropertySource
static void mongoDbProperties(DynamicPropertyRegistry registry) {
mongoDBContainer.start();
registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);
}
@Test
public void givenItem_whenGetItemIsCalled_thenMonoIsCached() {
Mono<Item> glass = itemService.save(new Item("glass", 1.00));
String id = glass.block().get_id();
Mono<Item> mono = itemService.getItem(id);
Item item = mono.block();
assertThat(item).isNotNull();
assertThat(item.getName()).isEqualTo("glass");
assertThat(item.getPrice()).isEqualTo(1.00);
Mono<Item> mono2 = itemService.getItem(id);
Item item2 = mono2.block();
assertThat(item2).isNotNull();
assertThat(item2.getName()).isEqualTo("glass");
assertThat(item2.getPrice()).isEqualTo(1.00);
}
@Test
public void givenItem_whenGetItemWithCacheIsCalled_thenMonoResultIsCached() {
Mono<Item> glass = itemService.save(new Item("glass", 1.00));
String id = glass.block().get_id();
Mono<Item> mono = itemService.getItem_withCache(id);
Item item = mono.block();
assertThat(item).isNotNull();
assertThat(item.getName()).isEqualTo("glass");
assertThat(item.getPrice()).isEqualTo(1.00);
Mono<Item> mono2 = itemService.getItem_withCache(id);
Item item2 = mono2.block();
assertThat(item2).isNotNull();
assertThat(item2.getName()).isEqualTo("glass");
assertThat(item2.getPrice()).isEqualTo(1.00);
}
@Test
public void givenItem_whenGetItemWithAddonsIsCalled_thenMonoResultIsCached() {
Mono<Item> glass = itemService.save(new Item("glass", 1.00));
String id = glass.block().get_id();
Mono<Item> mono = itemService.getItem_withAddons(id);
Item item = mono.block();
assertThat(item).isNotNull();
assertThat(item.getName()).isEqualTo("glass");
assertThat(item.getPrice()).isEqualTo(1.00);
Mono<Item> mono2 = itemService.getItem_withAddons(id);
Item item2 = mono2.block();
assertThat(item2).isNotNull();
assertThat(item2.getName()).isEqualTo("glass");
assertThat(item2.getPrice()).isEqualTo(1.00);
}
}