Posts 스프링 캐시
Post
Cancel

스프링 캐시

[spring] 스프링 캐시

캐시란 반복적으로 데이터를 불러올 때 지속적으로 DBMS 혹은 서버에 요청하는 것이 아닌 메모리에 데이터를 저장하였다가 데이터를 불러다가 쓰는 것을 말한다. 서버나 DBMS의 부담을 줄여주고, 메모리에 저장되어있기 때문에 많은 시스템에서 사용할수 있다.

캐시는 Long Tail 법칙에 따라 시스템 리소스 사용의 대부분을 차지하는 20%의 요청을 캐싱하면 시스템 전체가 매우 빨라진다고 할 수 있다.

17110B4350CC5EC51D


CacheManager

스프링 부트에서 spring-boot-starter-cache을 추가하여 구성할 수 있는 캐시 매니저이다. 기본적으로 별도의 추가적인 서드파티 모듈이 없는 경우에는 Local Memory에 저장이 가능한 ConcurrentMap 기반인 ConcurrentMapCacheManager가 빈으로 자동 생성된다.

이 외에도 EHCache, Redis 등의 서드 파티 모듈을 추가하면 EHCacheCacheManager, RedisCacheManager를 빈으로 등록하여 사용할 수 있다. 이렇게 하면 별도로 다른 설정 없이도 단순 Memory cache가 아닌 cache server를 대상으로 캐시를 저장할 수 있도록 지원하고 있다.

스프링 3.2 이상에서는 7개의 CacheManager 구현체를 지원한다

  • SimpleCacheManager
  • NoOpCacheManager
  • ConcurrentMapCacheManager
  • CompositeCacheManager : 한 개 이상의 캐시매니저를 선택해야할 떄 사용
  • EhCacheCacheManager
  • RedisCacheManager (스프링 Redis)
  • GemfireCacheManager (스프링 GemFire)

SimpleCacheManager 사용처

SimpleCacheManager는 단순히 캐시를 등록하여 사용하는데 사용할 수 있지만, 다른 캐시매니저와는 달리 다양한 캐시를 조합하여 등록할 수 있다는 점에서 편리할 수 있다.

1
2
3
4
5
6
7
8
9
10
// ConcurrentMapCacheManager
// 캐시의 이름만 등록할 수 있고, 모두 ConcurrnetMapCache로 등록된다.
new ConcurrentMapCacheManager("comment", "category", "user");

// SimpleCacheManager
// 캐시를 직접 등록하여, 다양한 조합의 캐시로 사용할 수 있다.
SimpleCacheManager cm = new SimpleCacheManager();
cm.setCaches(Arrays.asList(
      defaultCache(),
      exceptionCache()));


스프링 캐시 애노테이션

@EnableCache

Annotation 기반 캐싱 설정을 사용함을 명시하는 애노테이션이다. (내부적으로는 Sprign AOP 사용)

속성

  • proxyTargetClass : 클래스 기반의 Proxy 생성 여부. 디폴트는 false
    • false : JDK Dynamic Proxy 사용. (interface 기반)
    • true : CGLIB Proxy 사용 (class 기반)
  • Mode : 위빙 모드에 대한 설정. 디폴트는 PROXY
    • PROXY : 기본의 spring AOP 방식을 이용한 RTW 방식 사용
    • ASPECTJ : aspectj 라이브러리를 이용한 CTW, LTW 방식 지원
  • order : AOP order 설정. 디폴트는 Integer.MAX_VALUE


@Cacheable

1
2
3
4
5
@Target(value={TYPE,METHOD})
@Retention(value=RUNTIME)
@Inherited
@Documented
public @interface Cacheable

메서드에 붙어, 해당 메서드가 호출된 결과가 캐시 될 수 있다고 알려주는 애노테이션이다.

동작

지시된 메서드가 호출될 때마다, 주어진 파라미터로 이미 호출된 적이 있는지 확인하는 과정이 추가된다. 기본적으론 메서드의 파라미터를 캐시 키로 사용하지만, SpEL expressionkey()로 적용될 수 있다. 또는 커스텀 KeyGenerator 구현이 적용될 수도 있다.

만약 주어진 캐시 키로 값을 찾을 수 없다면, 메서드는 정상적으로 호출되고 반환값을 만든다. 그리고 그 반환값은 캐시 저장소에 저장된다.

주의 : Optional로 감싸진 값은 자동으로 unwrap 된다. Optional 값이 존재하면 그 값이 저장되고, 없으면 null이 저장된다.

속성

  • cacheManager : 사용할 CacheManager를 지정
  • cacheNames : 메서드의 반환값이 저장될 떄 사용될 캐시의 이름들
  • cacheResolver : 커스텀 CacheResolver의 빈 이름(CacheResolver : Cache키에 대한 결과값을 돌려주는 리졸버)
  • condition : 메서드 결과값이 캐싱되도록 하는 조건. SpEL로 표현
  • unless : 메서드 결과값이 캐싱되지 않도록 하는 조건. SpEL로 표현
    • ex) unless = “#id == null” –> id가 null일 땐 캐싱이 일어나지 않음.
  • key : 동적으로 키를 계산할 때 사용되는 SpEL 표현. 같은 캐시명을 사용할 때 구분되는 구분 값이다.
  • keyGenerator : 커스텀 KeyGenerator의 빈 이름. 특정 로직에 의해 cache key를 만들고자할 때 사용한다. key와 함께 사용할 수 없음.
  • sync : 복수의 스레드가 같은 키로 값을 가져오려고 할 때 동기화할 것인지 표시
  • value : cacheNames()의 alias

@CacheEvict

메서드 실행 시, 해당 캐시를 삭제

속성

  • Value, cacheName : 삭제할 캐시 명
  • key : 같은 캐시명을 사용할 때 구분되는 구분값.
  • keyGenerator
  • cacheManager
  • cacheResolver
  • condition : SpEL 표현식을 통해 특정 조건에 부합하는 경우에만 캐시 사용. 연산 조건이 true일 때문 캐시 삭제
  • allEntries : Cache key에 대한 전체 데이터 삭제 여부
  • beforeInvocation : true면 메서드 실행 이전에 캐시 삭제. false면 메서드 실행 이후 삭제

@CachePut

  • 캐시가 존재하는지 검사하지않고 항상 메서드 실행하고 결과값을 캐시에 저장. 캐시를 갱신할 때 사용한다.
  • 보통 @Cacheable과 @CachePut 을 동시에 사용하지 않는다. (실행 순서에 따라 다른 결과가 나올 수 있기에)
  • @CachePut은 캐시 생성용으로만 사용한다.

속성

  • Value, cacheName : 삭제할 캐시 명
  • key : 같은 캐시명을 사용할 때 구분되는 구분값.
  • keyGenerator
  • cacheManager
  • cacheResolver
  • condition : SpEL 표현식을 통해 특정 조건에 부합하는 경우에만 캐시 사용. 연산 조건이 true일 때문 캐시 삭제
  • unless : 메서드 결과값이 캐싱되지 않도록 하는 조건. SpEL로 표현

@Caching

  • @Cacheable, @CacheEvict, @CachePut을 여러개 지정해야하는 경우 사용.
  • 조건식이나 표현식이 다른 경우에 사용됨.
  • 여러가지의 key에 대한 캐시를 중첩적으로 삭제해야할 때 사용.

속성

  • cacheable[] : 등록할 @Cacheable 등록
  • put[] : 등록할 @CacheEvict 등록
  • evict[] : 등록할 @CachePut 등록

@CacheConfig

  • 클래스 단위로 캐시 설정을 동일하게 하는데 사용
  • 보통 CacheManager가 여러 개인 경우에 사용

속성

  • cacheNames : 캐시명
  • keyGenerator
  • cacheManater
  • cacheResolver


사용

org.springframework.cache.annotation 아래 있는 애노테이션으로, spring-boot-starter-cache 의존성을 추가해줘야한다.

compile('org.springframework.boot:spring-boot-starter-cache')

config 추가

1
2
3
4
5
6
7
8
9
10
11
@Configuration
@EnableCaching
public class CachingConfig {
    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager.setCaches(Arrays.asList(
                new ConcurrentMapCache("article")));
        return cacheManager;
    }
}

캐시 적용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Service
public class ArticleService {
    @Cacheable(value = "article")
    public String getArticles(long articleId){
			String article = "";

			System.out.println( code +  " article을 조회합니다 ...");
			if(articleId == 1){
				article = "첫번째 아티클"
			}
			else if(articleId == 2){
				article = "두번째 아티클";
			}
			else if(articleId == 3){
				article = "세번째 아티클";
			}
    }
}


출처

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/cache/annotation/Cacheable.html

https://bob-full.tistory.com/23

https://jaehun2841.github.io/2018/11/07/2018-10-03-spring-ehcache/#Cache%EB%9E%80

https://shinsunyoung.tistory.com/50

This post is licensed under CC BY 4.0 by the author.

PathPattern과 servletPath

Content-Disposition

Comments powered by Disqus.