캐시는 미래의 데이터 요청에 빠르게 응답하기 위한 데이터 저장의 한 방법이다. (wikipedia)
캐시의 활용은 다양한데, 동일한 데이터를 계속해서 활용할 경우 계산 작업을 중복해서 하지 않도록 하거나 계산 시간이 오래 걸리는 작업을 미리 처리하고 추후 요청이 왔을 때 응답하도록 할 수 있다.
spring에서는 cache 서비스를 추상화하며 여러 데이터 저장소를 활용할 수 있도록 구성하였다.
org.springframework.cache.Cache 와 org.springframework.cache.CacheManager 인터페이스로 구체화된다.
해당 추상화에 대한 여러가지 구현들이 있는데 우리는 가장 기본이 되는 JDK의 java.util.concurrent.ConcurrentMap를 활용한 구현법을 살펴보자. 그 외에도 Redis, Couchbase, JCache, EhCache 2.x 등 여러 종류가 있으니 자세한 사항은 spring 문서를 찾아보도록 하자.
지금부터는 annotation을 사용해 선언적 방법으로 cache 설정을 해보도록 하자.
- @Cacheable : 캐시 설정
- @CacheEvict : 캐시 삭제
- @CachePut : 캐시 업데이트
- @Caching : 여러개의 cache 동작을 적용
- @CacheConfig : 클래스 레벨에서 캐시 설정의 공유
@Cacheable
캐시 하고자 하는 메서드에 @Cacheable를 선언하면 해당 메서드가 캐싱이 된다. 메서드가 수행되었는지 판단하고 수행되었다면 저장한 결과를 리턴하도록 한다. 선언을 할 때 연관된 이름이 필요하다. 이름은 cacheNames로 정의한다.
@Cacheable("books")
public Book findBook(ISBN isbn) {…}
cache는 기본적으로 key-value 구조로 되어 있다. 저장된 캐시에 접근하기 위해서는 적절한 key값이 필요하다. key값을 지정하지 않을 경우 아래와 같은 알고리즘으로 구현된 KeyGenerator에 의해서 key값을 만들어준다.
- 파라미터가 없을 경우, SimpleKey.EMPTY
- 파라미터가 하나일 경우, 인스턴스를 리턴한다.
- 파라미터가 하나 이상일 경우, 모든 파라미터를 포함한 SimpleKey를 리턴한다.
아래 코드는 key 값을 지정해 준 것이다.
키를 설정한 방법은 Spring Expression Language (SpEL)를 따른다.
@Cacheable(cacheNames="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
@Cacheable(cacheNames="books", key="#isbn.rawNumber")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
@Cacheable(cacheNames="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
만약 동일한 파라미터를 가진 2개의 함수에 key값을 지정하려고 하면 어떻게 할까?
다음 stackoverflow에서는 2가지의 해결법을 제안하고 있다.
[방법 1]. KeyGenerator 구현을 통해 key 구분
public class CustomKeyGenerator implements KeyGenerator{
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder key = new StringBuilder();
//include method name in key
key.append(method.getName());
if (params.length > 0) {
key.append(';');
for (Object argument : params) {
key.append(argument);
key.append(';');
}
}
return key.toString();
}
}
앞서 기본 KeyGenerator가 있다고 했는데, 함수이름과 파라미터를 활용한 새로운 KeyGenerator를 구현하는 것이다.
새롭게 구현된 CustomKeyGenerator를 Bean으로 등록하고 @Cacheable 설정시 사용한다.
[방법 2]. 메서드이름과 파라미터를 활용해 SpEL 설정.
@Component
public class StatService {
@Cacheable(value="statCalc",key="#root.method.name.concat(':').concat(#param"))
public int getMeth1(int param) {
// LOGIC1
}
@Cacheable(value="statCalc",key="#root.method.name.concat(':').concat(#param"))
public int getMeth2(int param) {
// LOGIC2
}
}
두번째 방법은 SpEL로 key를 작성시 함수이름과 파라미터를 포함해서 구분된 key값을 만들어 주는 것이다.
@CachePut
캐시의 값을 업데이트 하고자 할 때 사용한다. @CachePut을 선언한 메서드를 항상 실행되고 캐시값을 바꾸도록 되어 있다.
한가지 주의할 점은 @CachePut과 @Cacheable을 동시에 선언하면 안된다. @Cacheable은 캐시를 사용하여 실행을 건너뛸 수 있지만, @CachePut은 실행을 강제한다.
@CacheEvict
@CacheEvict는 캐시를 지우는 역할을 한다. 캐시에서 오래된 데이터 또는 사용하지 않은 데이터를 제거하는데 유용하다. 추가 파라미터로 allEntries는 전체 캐시를 지울지 여부를 선택할 수 있다.
@CacheEvict(cacheNames="books", allEntries=true)
public void loadBooks(InputStream batch)
[참고]
반응형
'Framework > spring' 카테고리의 다른 글
[spring boot] spring boot configuration 이해 (0) | 2017.08.30 |
---|---|
[spring] lifecycle mechanisms (0) | 2017.08.29 |
스프링 팁: *Utils 클래스 활용 (0) | 2017.04.03 |
[spring security] Controller에서 Principal 가져오기 (0) | 2016.03.24 |