복붙노트

[SPRING] Cacheable 주석의 조건에서 키를 사용하려면 어떻게해야합니까?

SPRING

Cacheable 주석의 조건에서 키를 사용하려면 어떻게해야합니까?

@cacheable 주석을 사용하여 함수의 결과를 캐싱합니다. 3 가지 다른 캐시가 있으며 각각의 키는 메소드에 인수로 연결된 현재 로그인 한 사용자의 사용자 ID입니다. 특정 이벤트에서 특정 사용자 ID로 시작하는 키가있는 모든 캐시 항목을 제거하려고합니다. 예 :

@Cacheable(value = "testCache1", key = "'abcdef'")

캐시 퇴거 주석을 다음과 같이하고 싶습니다.

@CacheEvict(value = "getSimilarVendors", condition = "key.startsWith('abc')")

그러나 이것을 구현하려고하면 오류가납니다.

Property or field 'key' cannot be found on object of type'org.springframework.cache.interceptor.CacheExpressionRootObject' - maybe not      public?

이것을 구현하는 올바른 방법은 무엇입니까?

해결법

  1. ==============================

    1.모든 Spring Cache 주석 (즉 @Cacheable, @CacheEvict 등)은 작업 당 1 개의 캐시 항목에서 작동합니다. @CacheEvict는 전체 캐시를 지우는 것을 지원하지만 (allEntries 속성은이 경우 키를 무시하지만) 단일 작업으로 키 패턴을 기반으로 부분 항목 집합을 지우는 것이 선택적 (유능하지 않음) 설명했다.

    모든 Spring Cache 주석 (즉 @Cacheable, @CacheEvict 등)은 작업 당 1 개의 캐시 항목에서 작동합니다. @CacheEvict는 전체 캐시를 지우는 것을 지원하지만 (allEntries 속성은이 경우 키를 무시하지만) 단일 작업으로 키 패턴을 기반으로 부분 항목 집합을 지우는 것이 선택적 (유능하지 않음) 설명했다.

    이것의 주된 이유는 evict (key : Object) 메소드가 단일 키 인수를 취하는 Spring Cache 인터페이스 추상화 자체입니다. 그러나 기술적으로 실제로는 기본 캐시 구현 (예 : GemfireCache)에 따라 달라지며, 이는 특정 패턴과 일치하는 모든 항목에 대해 퇴출을 지원해야합니다. 일반적으로 대부분의 캐시에는 해당되지 않습니다 (예 : GemFire가 아닌 경우). Google Guava 캐시 용이 아니라 여기 및 여기 참조).

    그것은 당신이 절대적으로 당신의 목표를 달성 할 수 없다는 말은 아닙니다. 그것은 바로 out-of-the-box 지원되는 무언가가 아닙니다.

    흥미로운 점은 접근 방식에 기술적 인 문제가 없다는 것입니다. 조건에 따라 원하는대로 정렬 할 수 있습니다. 캐시 퇴거는 키가 조건을 충족하는 경우에만 발생합니다. 그러나 @CacheEvict 주석이 달린 메서드는 "키"가 누락되어 오류가 발생합니다. 그래서, 다음과 같은 것이 당신의 상태에서 SpEL을 만족시킬 것입니다 ...

    @CacheEvict(condition = "#key.startsWith('abc')")
    public void someMethod(String key) {
      ...
    }
    

    그러나이 경우 인수로 키를 지정해야합니다. 그러나 특정 키를 원하지 않으면 여러 키와 일치하는 패턴을 원하게됩니다. 그래서, 조건을 잊어 버리고 그냥 사용하십시오 ...

    @CacheEvict
    public void someMethod(String keyPattern) {
      ...
    }
    

    예를 들어, Guava를 캐싱 공급자로 사용하면 GuavaCache를 확장하는 "사용자 지정"구현을 제공해야합니다.

    public class CustomGuavaCache extends org.springframework.cache.guava.GuavaCache {
    
      protected boolean isMatch(String key, String pattern) {
        ...
      }
    
      protected boolean isPattern(String key) {
        ...
      }
    
      @Override
      public void evict(Object key) {
        if (key instanceof String && isPattern(key.toString()))) {
            Map<String, Object> entries = this.cache.asMap();
            Set<String> matchingKeys = new HashSet<>(entries.size());
            for (String actualKey : entries.keySet()) {
              if (isMatch(actualKey, key.toString()) {
                matchingKeys.add(actualKey);
              }
            }
            this.cache.invalidateAll(matchingKeys);
        }
        else {
          this.cache.invalidate(key);
        }
      }
    }
    

    이제 GuavaCacheManager를 확장하여 "사용자 정의"GuavaCache (CustomGuavaCache)를 플러그인하십시오.

    public class CustomGuavaCacheManager extends org.springframework.cache.guava.GuavaCacheManager {
    
      @Override
      protected Cache createGuavaCache(String name) {
        return new CustomGuavaCache(name, createNativeGuavaCache(name), isAllowNullValues());
      }
    }
    

    이 접근법은 Guava의 Cache의 invalidateAll (keys : Iterable) 메소드를 이용합니다. 물론, 자바의 Regex 지원을 사용하여 isMatch (key, pattern) 메소드에서 제거 할 원하는 키에 "일치"를 수행 할 수 있습니다.

    그래서, 나는 이것을 테스트하지는 않았지만, 이것 (또는 비슷한)은 (거의) 당신이 원하는 것을 달성해야합니다 (손가락이 엇갈린 ;-)

    희망이 도움이!

    건배, 남자

  2. from https://stackoverflow.com/questions/32460606/how-do-i-use-the-key-in-a-condition-in-cacheable-annotation by cc-by-sa and MIT license