티스토리 뷰

스프링, 자바

스프링 캐쉬

killog 2020. 10. 3. 22:32
반응형

개요

Spring 3.1부터 Cache Service는 Cache 추상화(CacheManager Interface)와 Cache 추상화를 Java메소드에 제공할 수 있는 @Cacheable을 제공한다. Cache 추상화는 Spring의 트랜잭션기능과 유사하게 코드의 변화를 최소화하면서 Proxy를 통해 동작하게끔 한다. Cache 구현체가 아닌 Cache추상화만을 제공하며 실제 Cache Data저장소는 EhCache와 ConcurrentMap을 지원한다.

  • Cache Configuration : Cache설정을 통하여 어떠한 Cache Data저장소를 쓸 것인지 결정할 수 있다. (EhCache/ConcurrentMap)

  • Cache Manager : CacheManager를 통해 설정과 상관없이 동일한 코드로 Cache에 접근할 수 있다.

  • Cache Annotation : 메소드의 Cache Annotation을 통해 쉽게 Cache데이터를 저장/삭제할 수 있다.

설명

Cache를 설정하여 CacheManager를 통해 Cache에 접근하는 방법에 대하여 알아보고, 자바메소드를 Caching하는 @Cacheable에 대하여 알아본다.

Cache Configuration

EhCache

Spring에서는 EhCache를 지원하는 CacheManager로써 EhCacheCacheManager를 제공한다.

<EhCache 설정>

<cache:annotation-driven cache-manager="cacheManager" /> 
<!-- EhCache를 저장소로 사용하는 Cache Manager -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"></property>
</bean>
<!-- Ehcache library setup -->
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:config-location="classpath:springframework/cache/ehcache/ehcache.xml" />

Ehcache.xml에서 defaultCache저장소와 추가 Cache저장소의 설정을 한다. EhCAche는 비록 ConcurrentMap보다 속도는 느리지만 Cache관리기능 측면에서 유용하여 EhCache를 추천한다.

  • 프로젝트에서는 Cache의 사용에 대하여 개발자의 가이드가 필요하다. 업무별/서비스별 Cache저장소를 분리하여 Cache데이터를 관리하도록 하며, 적용케이스에 대하여 가이드하여야 한다.

<ehcache.xml>

<ehcache…> 
        <defaultCache maxElementsInMemory="10000" 
        eternal="false" 
        timeToIdleSeconds="120" 
        timeToLiveSeconds="120" 
        overflowToDisk="true"
        diskSpoolBufferSizeMB="30"
        maxElementsOnDisk="10000000"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU"
        statistics="false" />
<cache name="ehcache" …>

ConcurrentMap

Spring에서는 ConcurrentMap을 지원하는 SimpleCacheManager를 제공한다.

<CacheManager설정>

<cache:annotation-driven cache-manager="cacheManager"/>
<!-- ConcurrentMap을 저장소로 사용하는 Cache Manager -->
<bean id="cacheManager" 
class="org.springframework.cache.support.SimpleCacheManager"> 
<property name="caches"> 
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
p:name="default"/> 
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" 
p:name="books"/> </set> </property> </bean>

Cache Annotation을 위한 annotation-driven 설정

Cache Annotation으로 Cache를 적용하기 위해서는 반드시 <cache:annotatioin-driven>을 붙여주어야한다. 이 네임스페이스는 AOP를 사용해서 캐시 기능을 다양한 방법으로 설정할 수 있는 옵션을 제공한다. 이 설정은 Transaction에 사용되는 <tx:annotation-driven>과 비슷하다.

속성기본값설명

cache-manager cacheManager 사용할 CacheManager의 이름. CacheManager의 Bean id가 cacheManager가 아닐 경우, 설정해야한다.
mode proxy 스프링 AOP를 사용하는 설정이며, “aspect”를 사용할 수도 있다.
proxy-target-class false false인 경우, JDK의 인터페이스 기반 프록시를 사용한다. true를 사용하면 클래스 기반 프록시를 사용한다.
order Ordered.LOWEST_PRECEDENCE @Cacheable/@CacheEvict메소드의 Cache advice가 적용되는 순서
  • <cache:annotation-driven/>은 오로지 이것이 정의된 동일 ApplicationContext안의 bean에서 @Cacheable@CacheEvict을 찾는다. 즉, <cache:annotation-driven>을 DispatcherServlet을 위한 WebApplicationContext에 선언했을때 @Cacheable/@CacheEvict는 controller내부에서만 식별된다.

CacheManager를 통한 Cache접근

ehCache, concurrentMap의 설정과 상관없이 코드상으로 동일한 CacheManager인터페이스로 bean을 주입받아 사용할 수 있다.

<CacheManager 의 사용>

import org.springframework.cache.CacheManager; 

@Autowired private CacheManager cacheManager; 
Cache cache = cacheManager.getCache("cache명");

@Cacheable

자바메소드에 @Cacheable을 설정함으로써 Caching할 수 있다. 타겟메소드가 호출되었을 때, 캐시에 해당 메서드가 이미 동일한 인자로 있는지 확인하고, 만약 있다면 메소드를 호출하지 않고 캐시해둔 결과를 Proxy에서 반환하게 된다.

Java Method에 적용가능한 Cache Annotation은 다음과 같다.

  • @Cacheable : Cache에 메소드 데이터를 생성한다.

  • @CacheEvict : Cache에 메소드 데이터를 삭제한다.

@Cacheable 사용방법

별다른 조건없이 호출되는 모든 인자를 caching하고자 할 때는 아래와 같이 cache명만 쓰면 된다. 이 코드는 Cache이름이 “books”인 cache저장소를 사용하였다. 메소드가 호출될 때 매번 “books”에 Cache데이터를 확인하고 이미 실행된 적이 있는지를 확인한다. 만약 “books”에 데이터가 있으면 그 값을 반환하게 된다.

기본

@Cacheable("books") 
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

Cache되는 저장소를 여러개 정의할 수도 있다. 아래의 코드에서는 findBook메소드 호출 시 “books”와 “isbns” 두 군데에 캐시데이터가 저장된다.

<여러 cache 저장소에 caching>

@Cacheable({ "books", "isbns" }) public Book findBook(ISBN isbn) {...}

Cache Abstraction Key생성

Cache는 키-값으로 저장되며, 캐시된 메소드를 호출시마다 키를 통해 값을 가져오므로 캐시를 찾을 수 있는 키가 생성되어야한다. 별도의 커스텀키가 정의되지 않으면 default로 다음과 같은 알고리즘 기반의 KeyGenerator를 사용하여 Key를 생성한다.

  • 매개변수가 아무것도 없으면 0을 반환한다.

  • 매개변수가 하나면, 그 인스턴스를 반환한다.

  • 매개변수가 둘 이상이면, 모든 매개변수의 Hash로 계산된 키를 반환한다.

이 외에 다른 기본키를 생성하려면 org.springframework.cache.KeyGenerator 인터페이스를 구현하면 된다.

 

Custom key 추가

@Cacheable을 적용한 메소드의 인자가 여러개일 때 Key로 사용할 것을 SpEL로 명시할 수 있다.

@Cacheable(value="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)     

@Cacheable(value="books", key="#isbn.rawNumber") 
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)   

@Cacheable(value="books", key="T(someType).hash(#isbn)") 
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

Conditional 추가

Conditional을 주어서 그 값이 true이면 caching을 하고, false이면 caching을 하지 않기 때문에 호출시 매번 메소드내부가 실행된다. Conditional에서는 SpEL사용이 가능하며 Condition과 Unless를 쓸 수 있다. condition과는 달리 unless는 메소드의 결과값 반환 시점에 결과값을 확인하여 caching여부를 결정하게 된다.

@Cacheable(value="book", condition="#name.length < 32")
public Book findBook(String name)

@Cacheable(value="book", condition="#name.length < 32", unless="#result.hardback")
public Book findBook(String name)

Conditional에 쓰는 SpEL의 설명은 다음과 같다.

명칭위치설명예제

methodName root객체 호출되는 메소드명 #root.methodName
method root객체 호출되는 메소드 #root.method.name
target root객체 호출되는 타겟오브젝트 #root.target
targetClass root객체 호출되는 타겟 클래스 #root.targetClass
args root객체 타겟을 호출 시 사용되는 인자들(배열) #root.args[0]
caches root객체 현재 메소드가 실행되는 캐시들의 집합 #root.caches[0].name
argument name 평가 context 메소드 인자명을 사용할 수 없을 때 대신 a<#arg>로 대체하여 사용할 수 있다. #arg는 0부터 시작하는 인자의 인덱스를 나타난다. iban 또는 a0 (p<#arg>로도 사용가능)
result 평가 context 메소드호출 결과. unless와 cache evict표현에서만 사용가능하다. #result

@CacheEvict

@CacheEvict는 @Cacheable과 반대로 cache저장소의 데이터를 제거함으로써 사용하지 않는 데이터를 정리하는데 유용하다. @CacheEvict는 캐시삭제를 수행할 메서드에 선언한다. @CacheEvict도 여러개의 캐시를 명시할 수 있으며, key와 condition을 사용할 수 있다. 또한 allEntries속성은 키값으로 Cache Entrie하나만 비우는 것이 아니라 캐시영역의 모든 Entrie를 비우도록 한다. 이 경우에는 키를 명시하더라도 이를 무시하고 모든 Entrie를 비우게 된다.

@CacheEvict(value = "books", allEntries=true) 
public void loadBooks(InputStream batch)

@CachePut

메소드의 흐름을 방해하지 않고 Cache에 저장하거나 업데이트를 해야하는 경우, @CachePut을 사용한다. 즉, 메소드는 항상 실행되고 그 결과가 캐시에 저장된다. @CachePut은 @Cacheable과 동일한 옵션을 제공하며, Cache에 저장하는것보다는 메소드의 흐름을 최적화하는데 사용되어야 한다.

@Cacheable과 함께 사용하는것은 일반적으로 권장하지 않는다.

@Caching

다수의 Cache annotation을 쓰고자 할 때 @Caching을 쓴다. @Cacheable, @CacheEvic, @CachePut을 지원한다.

@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") }) 
public Book importBooks(String deposit, Date date)

 

참고 링크

www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte2:fdl:cache_abstraction

반응형

'스프링, 자바' 카테고리의 다른 글

Lombok  (0) 2020.10.04
스프링 도큐먼트  (0) 2020.10.03
스프링 캐쉬 사용법  (0) 2020.10.03
BaseEntity.java  (0) 2020.10.03
[패스트캠퍼스 수강 후기] 자바 인강 100% 환급 챌린지 50회차 미션  (0) 2020.09.28
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함