Spring Webflux and @Cacheable Annotation - moved to new package
This commit is contained in:
7
spring-5-webflux-2/README.md
Normal file
7
spring-5-webflux-2/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## Spring 5 WebFlux 2
|
||||
|
||||
This module contains articles about Spring 5 WebFlux
|
||||
|
||||
## Relevant articles:
|
||||
|
||||
- [Spring Webflux and @Cacheable Annotation](https://www.baeldung.com/spring-webflux-cacheable)
|
||||
102
spring-5-webflux-2/pom.xml
Normal file
102
spring-5-webflux-2/pom.xml
Normal file
@@ -0,0 +1,102 @@
|
||||
<?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>
|
||||
<artifactId>spring-5-webflux-2</artifactId>
|
||||
<name>spring-5-webflux-2</name>
|
||||
<url>http://www.baeldung.com</url>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit</groupId>
|
||||
<artifactId>junit-bom</artifactId>
|
||||
<version>${junit-jupiter.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-plaform-commons</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</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>2.9.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
|
||||
</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>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
50
spring-5-webflux-2/src/main/java/caching/Item.java
Normal file
50
spring-5-webflux-2/src/main/java/caching/Item.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package 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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package caching;
|
||||
|
||||
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface ItemRepository extends ReactiveMongoRepository<Item, String> {
|
||||
}
|
||||
42
spring-5-webflux-2/src/main/java/caching/ItemService.java
Normal file
42
spring-5-webflux-2/src/main/java/caching/ItemService.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
logging.level.org.springframework.data.mongodb.core.ReactiveMongoTemplate=DEBUG
|
||||
logging.level.org.springframework.cache=TRACE
|
||||
31
spring-5-webflux-2/src/main/resources/logback.xml
Normal file
31
spring-5-webflux-2/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="Console"
|
||||
class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>
|
||||
%black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
|
||||
</Pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="AccessLog" class="ch.qos.logback.core.FileAppender">
|
||||
<file>netty-access.log</file>
|
||||
<encoder>
|
||||
<pattern>%msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="Async" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="AccessLog"/>
|
||||
</appender>
|
||||
|
||||
<logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
|
||||
<appender-ref ref="Console"/>
|
||||
<appender-ref ref="Async"/>
|
||||
</logger>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="Console"/>
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,95 @@
|
||||
package caching;
|
||||
|
||||
|
||||
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.ActiveProfiles;
|
||||
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
|
||||
@ActiveProfiles("cache")
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
13
spring-5-webflux-2/src/test/resources/logback-test.xml
Normal file
13
spring-5-webflux-2/src/test/resources/logback-test.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>
|
||||
%black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
|
||||
</Pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
<root level="info">
|
||||
<appender-ref ref="Console"/>
|
||||
</root>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user