簡體   English   中英

Spring Cache不適用於抽象類

[英]Spring Cache not working for abstract classes

我試圖在抽象類中使用Spring Cache但它不起作用,因為從我所看到的,Spring正在抽象類中搜索CacheNames。 我有一個REST API,它使用服務層和dao層。 我們的想法是為每個子類設置不同的緩存名稱。

我的抽象服務類看起來像這樣:

    @Service
    @Transactional
    public abstract class AbstractService<E> {

...

    @Cacheable
    public List<E> findAll() {
        return getDao().findAll();
    }
}

抽象類的擴展名如下所示:

@Service
@CacheConfig(cacheNames = "textdocuments")
public class TextdocumentsService extends AbstractService<Textdocuments> {
...
}

所以當我用這段代碼啟動應用程序時,Spring給了我以下異常:

Caused by: java.lang.IllegalStateException: No cache names could be detected on 'public java.util.List foo.bar.AbstractService.findAll()'. Make sure to set the value parameter on the annotation or declare a @CacheConfig at the class-level with the default cache name(s) to use.
    at org.springframework.cache.annotation.SpringCacheAnnotationParser.validateCacheOperation(SpringCacheAnnotationParser.java:240) ~[spring-context-4.1.6.RELEASE.jar:?]

我認為這是因為Spring在抽象類上搜索CacheName,盡管它是在子類上聲明的。

試着用

 @Service
 @Transactional
 @CacheConfig
        public abstract class AbstractService<E> {
    }

導致同樣的例外; 運用

 @Service
 @Transactional
 @CacheConfig(cacheNames = "abstractservice")
        public abstract class AbstractService<E> {
    }

沒有例外,但Spring Cache為每個子類使用相同的緩存名稱,並忽略在子類上定義的緩存名稱。 有什么想法可以解決這個問題?

這個問題已在另一個問題中得到解決,而不是關於抽象類以及更多關於框架能夠確定使用哪個緩存的能力。

長話短說(引用Spring文檔 )你缺少適用CacheResolver抽象類層次結構的CacheResolver

從Spring 4.1開始,緩存注釋的value屬性不再是必需的,因為無論注釋的內容如何,​​CacheResolver都可以提供此特定信息。

因此,您的抽象類應該定義緩存解析器,而不是直接聲明緩存名稱。

abstract class Repository<T> {
    // .. some methods omitted for brevity

    @Cacheable(cacheResolver = CachingConfiguration.CACHE_RESOLVER_NAME)
    public List<T> findAll() {
        return getDao().findAll();
    }
}

解析器確定用於截獲的方法調用的Cache實例。 一個非常天真的實現可以使用目標存儲庫bean(按名稱)並將其用作緩存名稱

class RuntimeCacheResolver
        extends SimpleCacheResolver {

    protected RuntimeCacheResolver(CacheManager cacheManager) {
        super(cacheManager);
    }

    @Override
    protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) {
        return Arrays.asList(context.getTarget().getClass().getSimpleName());
    }
}

這樣的解析器需要一個明確的配置:

@Configuration
@EnableCaching
class CachingConfiguration extends CachingConfigurerSupport {

    final static String CACHE_RESOLVER_NAME = "simpleCacheResolver";

    @Bean
    @Override
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager();
    }

    @Bean(CACHE_RESOLVER_NAME)
    public CacheResolver cacheResolver(CacheManager cacheManager) {
        return new RuntimeCacheResolver(cacheManager);
    }
}

創建了一個Gist ,它更詳細地描述了整個概念。

放棄

以上片段僅用於演示,旨在提供方向而不是提供完整的解決方案。 上面的緩存解析器實現非常幼稚,並沒有考慮很多事情(比如方法參數等)。 我永遠不會在生產環境中使用它。

Spring處理緩存的方式是通過代理,其中@Cacheable注釋聲明緩存,以及在運行時處理的命名信息。 通過提供給緩存解析器的運行時信息來解析緩存(毫不奇怪,它類似於經典AOP的InvocationContext的一些相似之處)。

public interface CacheOperationInvocationContext<O extends BasicOperation> {
    O getOperation();
    Object getTarget();
    Method getMethod();
    Object[] getArgs();
}

通過getTarget()方法,可以確定代理哪個bean,但在現實生活中,應該考慮更多信息,以提供可靠的緩存(如方法參數等)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM