From 4a1f6b132f844b8628ca7f71253868b4ceead1f5 Mon Sep 17 00:00:00 2001 From: Haroon Khan Date: Tue, 4 May 2021 17:10:01 +0100 Subject: [PATCH] [BAEL-4868] Use Redis as cache store --- pom.xml | 2 + spring-caching-2/README.md | 1 + spring-caching-2/pom.xml | 66 +++++++++++++++ .../baeldung/caching/redis/CacheConfig.java | 33 ++++++++ .../java/com/baeldung/caching/redis/Item.java | 21 +++++ .../caching/redis/ItemController.java | 19 +++++ .../caching/redis/ItemRepository.java | 6 ++ .../baeldung/caching/redis/ItemService.java | 19 +++++ .../caching/redis/RedisCacheApplication.java | 14 ++++ .../src/main/resources/application.properties | 12 +++ spring-caching-2/src/main/resources/data.sql | 1 + .../ItemServiceCachingIntegrationTest.java | 84 +++++++++++++++++++ .../src/test/resources/logback-test.xml | 5 ++ 13 files changed, 283 insertions(+) create mode 100644 spring-caching-2/README.md create mode 100644 spring-caching-2/pom.xml create mode 100644 spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java create mode 100644 spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java create mode 100644 spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java create mode 100644 spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java create mode 100644 spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java create mode 100644 spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java create mode 100644 spring-caching-2/src/main/resources/application.properties create mode 100644 spring-caching-2/src/main/resources/data.sql create mode 100644 spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java create mode 100644 spring-caching-2/src/test/resources/logback-test.xml diff --git a/pom.xml b/pom.xml index ab3c73ff8a..f4606ec368 100644 --- a/pom.xml +++ b/pom.xml @@ -623,6 +623,7 @@ spring-boot-rest-2 spring-caching + spring-caching-2 spring-cloud spring-cloud-bus @@ -1079,6 +1080,7 @@ spring-boot-rest-2 spring-caching + spring-caching-2 spring-cloud spring-cloud-bus diff --git a/spring-caching-2/README.md b/spring-caching-2/README.md new file mode 100644 index 0000000000..37095551a1 --- /dev/null +++ b/spring-caching-2/README.md @@ -0,0 +1 @@ +### Relevant articles: diff --git a/spring-caching-2/pom.xml b/spring-caching-2/pom.xml new file mode 100644 index 0000000000..6bb828e8bf --- /dev/null +++ b/spring-caching-2/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + spring-caching-2 + 0.1-SNAPSHOT + spring-caching-2 + war + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + 0.7.3 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.data + spring-data-commons + + + com.h2database + h2 + runtime + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-starter-cache + + + org.springframework.boot + spring-boot-starter-data-redis + + + + it.ozimov + embedded-redis + ${embedded.redis.version} + + + org.slf4j + slf4j-simple + + + test + + + diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java new file mode 100644 index 0000000000..89bdc2779d --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/CacheConfig.java @@ -0,0 +1,33 @@ +package com.baeldung.caching.redis; + +import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; + +import java.time.Duration; + +import static org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair; + +@Configuration +public class CacheConfig { + + @Bean + public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() { + return (builder) -> builder + .withCacheConfiguration("itemCache", + RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10))) + .withCacheConfiguration("customerCache", + RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5))); + } + + @Bean + public RedisCacheConfiguration cacheConfiguration() { + return RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofMinutes(60)) + .disableCachingNullValues() + .serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); + } + +} diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java new file mode 100644 index 0000000000..d6115a4833 --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/Item.java @@ -0,0 +1,21 @@ +package com.baeldung.caching.redis; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.Id; +import java.io.Serializable; + +@Data +@Entity +@AllArgsConstructor +@NoArgsConstructor +public class Item implements Serializable { + + @Id + String id; + + String description; +} diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java new file mode 100644 index 0000000000..63122c5938 --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemController.java @@ -0,0 +1,19 @@ +package com.baeldung.caching.redis; + +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@AllArgsConstructor +public class ItemController { + + private final ItemService itemService; + + @GetMapping("/item/{id}") + public Item getItemById(@PathVariable String id) { + return itemService.getItemForId(id); + } + +} diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java new file mode 100644 index 0000000000..d6222de621 --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemRepository.java @@ -0,0 +1,6 @@ +package com.baeldung.caching.redis; + +import org.springframework.data.repository.CrudRepository; + +public interface ItemRepository extends CrudRepository { +} diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java new file mode 100644 index 0000000000..6a59c7d74e --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/ItemService.java @@ -0,0 +1,19 @@ +package com.baeldung.caching.redis; + +import lombok.AllArgsConstructor; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +@Service +@AllArgsConstructor +public class ItemService { + + private final ItemRepository itemRepository; + + @Cacheable(value = "itemCache") + public Item getItemForId(String id) { + return itemRepository.findById(id) + .orElseThrow(RuntimeException::new); + } + +} diff --git a/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java b/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java new file mode 100644 index 0000000000..3b337def01 --- /dev/null +++ b/spring-caching-2/src/main/java/com/baeldung/caching/redis/RedisCacheApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.caching.redis; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; + +@SpringBootApplication +@EnableCaching +public class RedisCacheApplication { + + public static void main(String[] args) { + SpringApplication.run(RedisCacheApplication.class, args); + } +} diff --git a/spring-caching-2/src/main/resources/application.properties b/spring-caching-2/src/main/resources/application.properties new file mode 100644 index 0000000000..080185b620 --- /dev/null +++ b/spring-caching-2/src/main/resources/application.properties @@ -0,0 +1,12 @@ +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= + +# Enabling H2 Console +spring.h2.console.enabled=true +spring.h2.console.path=/h2 + +# Connection details +#spring.redis.host=localhost +#spring.redis.port=6379 diff --git a/spring-caching-2/src/main/resources/data.sql b/spring-caching-2/src/main/resources/data.sql new file mode 100644 index 0000000000..74e359b877 --- /dev/null +++ b/spring-caching-2/src/main/resources/data.sql @@ -0,0 +1 @@ +INSERT INTO ITEM VALUES('abc','ITEM1'); \ No newline at end of file diff --git a/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java b/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java new file mode 100644 index 0000000000..71a9729efd --- /dev/null +++ b/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java @@ -0,0 +1,84 @@ +package com.baeldung.caching.redis; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import redis.embedded.RedisServer; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@Import({ CacheConfig.class, ItemService.class }) +@ExtendWith(SpringExtension.class) +@ImportAutoConfiguration(classes = { CacheAutoConfiguration.class, RedisAutoConfiguration.class }) +@EnableCaching +class ItemServiceCachingIntegrationTest { + + private static final String AN_ID = "id-1"; + private static final String A_DESCRIPTION = "an item"; + + @MockBean + private ItemRepository mockItemRepository; + + @Autowired + private ItemService itemService; + + @Autowired + private CacheManager cacheManager; + + @Test + void givenRedisCaching_whenFindItemById_thenItemReturnedFromCache() { + Item anItem = new Item(AN_ID, A_DESCRIPTION); + given(mockItemRepository.findById(AN_ID)) + .willReturn(Optional.of(anItem)); + + Item itemCacheMiss = itemService.getItemForId(AN_ID); + Item itemCacheHit = itemService.getItemForId(AN_ID); + + assertThat(itemCacheMiss).isEqualTo(anItem); + assertThat(itemCacheHit).isEqualTo(anItem); + + verify(mockItemRepository, times(1)).findById(AN_ID); + assertThat(itemFromCache()).isEqualTo(anItem); + } + + private Object itemFromCache() { + return cacheManager.getCache("itemCache").get(AN_ID).get(); + } + + @TestConfiguration + static class EmbeddedRedisConfiguration { + + private final RedisServer redisServer; + + public EmbeddedRedisConfiguration() { + this.redisServer = new RedisServer(); + } + + @PostConstruct + public void startRedis() { + redisServer.start(); + } + + @PreDestroy + public void stopRedis() { + this.redisServer.stop(); + } + } + +} diff --git a/spring-caching-2/src/test/resources/logback-test.xml b/spring-caching-2/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..215403c6a5 --- /dev/null +++ b/spring-caching-2/src/test/resources/logback-test.xml @@ -0,0 +1,5 @@ + + + + +