Skip to content

Commit

Permalink
Merge pull request #539 from woowacourse-teams/refactor/#537
Browse files Browse the repository at this point in the history
[refactor] 지역 전체 조회에 대한 로컬 캐시 적용 (#537)
  • Loading branch information
Combi153 authored Nov 7, 2023
2 parents e7bef4e + a74f567 commit 6a8a9fd
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 5 deletions.
4 changes: 4 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-cache'

// configuration processor
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
Expand Down Expand Up @@ -66,6 +67,9 @@ dependencies {

// bcrypt
implementation 'org.mindrot:jbcrypt:0.4'

// caffeine
implementation 'com.github.ben-manes.caffeine:caffeine'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import dev.tripdraw.area.domain.Area;
import dev.tripdraw.area.domain.AreaRepository;
import dev.tripdraw.area.dto.AreaReqeust;
import dev.tripdraw.area.dto.AreaResponse;
import dev.tripdraw.area.dto.FullAreaResponse;
import dev.tripdraw.area.dto.FullAreaResponses;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -18,7 +19,6 @@
public class AreaService {

private final AreaRepository areaRepository;
private final OpenApiAreaDownloader openAPIAreaDownloader;

@Transactional(readOnly = true)
public AreaResponse read(String sido, String sigungu) {
Expand Down Expand Up @@ -66,6 +66,7 @@ private AreaResponse readAllUmdsOf(String sido, String sigungu) {
return AreaResponse.from(umds);
}

@CacheEvict(cacheNames = "areas", key = "'allAreas'")
public void create(List<Area> areas) {
long count = areaRepository.count();
if (count != 0) {
Expand All @@ -76,6 +77,8 @@ public void create(List<Area> areas) {
areaRepository.saveAll(areas);
}

@Cacheable(cacheNames = "areas", key = "'allAreas'")
@Transactional(readOnly = true)
public FullAreaResponses readAll() {
List<Area> areas = areaRepository.findAll();
List<FullAreaResponse> areaResponses = areas.stream()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dev.tripdraw.area.application;

import dev.tripdraw.area.domain.Area;
import dev.tripdraw.area.dto.AreaReqeust;
import dev.tripdraw.area.dto.AreaResponse;
import dev.tripdraw.area.dto.FullAreaResponses;
import java.util.List;
Expand Down
22 changes: 22 additions & 0 deletions backend/src/main/java/dev/tripdraw/common/cache/CacheType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package dev.tripdraw.common.cache;

public enum CacheType {

AREAS("areas", 1);

private final String cacheName;
private final int maximumSize;

CacheType(String cacheName, int maximumSize) {
this.cacheName = cacheName;
this.maximumSize = maximumSize;
}

public String cacheName() {
return cacheName;
}

public int maximumSize() {
return maximumSize;
}
}
37 changes: 37 additions & 0 deletions backend/src/main/java/dev/tripdraw/common/config/CacheConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package dev.tripdraw.common.config;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import dev.tripdraw.common.cache.CacheType;
import java.util.Arrays;
import java.util.List;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@EnableCaching
@Configuration
public class CacheConfig {

@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(caches());
return cacheManager;
}

private List<CaffeineCache> caches() {
return Arrays.stream(CacheType.values())
.map(cacheType -> new CaffeineCache(cacheType.cacheName(), cache(cacheType)))
.toList();
}

private Cache<Object, Object> cache(CacheType cacheType) {
return Caffeine.newBuilder()
.maximumSize(cacheType.maximumSize())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.mockito.Mockito.verify;

import dev.tripdraw.area.domain.Area;
import dev.tripdraw.area.domain.AreaRepository;
Expand All @@ -12,7 +11,6 @@
import dev.tripdraw.area.dto.FullAreaResponses;
import java.util.List;
import java.util.stream.Stream;

import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
Expand All @@ -21,6 +19,7 @@
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cache.CacheManager;
import org.springframework.transaction.annotation.Transactional;

@SuppressWarnings("NonAsciiCharacters")
Expand All @@ -35,6 +34,9 @@ class AreaServiceTest {
@Autowired
private AreaService areaService;

@Autowired
private CacheManager cacheManager;

@Test
void 전체_지역을_조회한다() {
// given
Expand All @@ -57,6 +59,30 @@ class AreaServiceTest {
));
}

@Test
void 전체_지역_조회_시_지역_정보를_캐싱한다() {
// given
Area 지역1 = areaRepository.save(new Area("서울시", "강남구", "개포동"));
Area 지역2 = areaRepository.save(new Area("서울시", "강남구", "강남동"));
Area 지역3 = areaRepository.save(new Area("서울시", "송파구", "잠실동"));
Area 지역4 = areaRepository.save(new Area("부산시", "강남구", "개포동"));

// when
areaService.readAll();

// then
FullAreaResponses responses = cacheManager.getCache("areas").get("allAreas", FullAreaResponses.class);

assertThat(responses.areas()).usingRecursiveComparison()
.isEqualTo(
List.of(
FullAreaResponse.from(지역1),
FullAreaResponse.from(지역2),
FullAreaResponse.from(지역3),
FullAreaResponse.from(지역4)
));
}

@MethodSource("paramsAndResponse")
@ParameterizedTest
void 해당하는_지역을_조회한다(List<String> sidoAndsigungu, AreaResponse response) {
Expand All @@ -82,6 +108,19 @@ class AreaServiceTest {
assertThatNoException().isThrownBy(() -> areaService.create(areas));
}

@Test
void 전체_행정구역_저장_시_지역_정보_캐시를_비운다() {
// given
areaRepository.save(new Area("서울시", "강남구", "개포동"));
areaService.readAll();

// when
areaService.create(List.of());

// then
assertThat(cacheManager.getCache("areas").get("allAreas")).isNull();
}

@Test
void 데이터가_존재하면_행정구역을_저장하지_않는다() {
// given
Expand Down

0 comments on commit 6a8a9fd

Please sign in to comment.