Spring Boot: java.lang.IllegalArgumentException: Cannot find cache named 'xxx' for CacheableOperation

問題

Spring Cloud for Amazon Web Services を利用しようとした所、
Spring Framework のキャッシュ機能に問題が発生しました。

それまでは普通にキャッシュを取得することができていたのですが、
下記のようなエラーログを吐き出して、キャッシュ取得に失敗します。

2015-10-19 10:41:59.170 ERROR 1663 --- [nio-8080-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Cannot find cache named 'ExampleCache' for CacheableOperation[public java.util.Optional com.example.common.dao.impl.ExampleDaoImpl.findByIdCache(java.lang.String)] caches=[ExampleCache] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless=''] with root cause

java.lang.IllegalArgumentException: Cannot find cache named 'ExampleCache' for CacheableOperation[public java.util.Optional com.example.common.dao.impl.ExampleDaoImpl.findByIdCache(java.lang.String)] caches=[ExampleCache] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless=''
    at org.springframework.cache.interceptor.AbstractCacheResolver.resolveCaches(AbstractCacheResolver.java:81)
    at org.springframework.cache.interceptor.CacheAspectSupport.getCaches(CacheAspectSupport.java:214)
    at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContext.<init>(CacheAspectSupport.java:555)
    at org.springframework.cache.interceptor.CacheAspectSupport.getOperationContext(CacheAspectSupport.java:227)
    at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContexts.<init>(CacheAspectSupport.java:500)
    at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
    at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    // ...

環境

  • java 1.8.0_60
  • spring boot 1.2.5.RELEASE (Spring v4.1.7.RELEASE)

原因

私のケースでは、意図したものではない CacheManager が呼ばれているのが原因でした。

キャッシュ機構を使えるようにするために、下記のようなビーン定義をしているかと思います。

    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager.setCaches(Lists.newArrayList(
                new ConcurrentMapCache("ExampleCache"),
                new ConcurrentMapCache("ExampleCache2")
        ));
        return cacheManager;
    }

これ自体は、EnableCaching (Spring Framework 4.2.2.RELEASE API) に記載されている通りの方法です。
通常は、この CacheManager が使われるのですが、
"spring-cloud-aws" をプロジェクトに組み込むと、これが使われなくなってしまうようです。

"spring-cloud-aws" の "ElastiCacheCacheConfigurer.java" 実装を見ていただきたいのですが、
こちらに AWS ElastiCache に関連する cacheManager が定義されています。

public class ElastiCacheCacheConfigurer extends CachingConfigurerSupport {

	//...

	@Override
	public CacheManager cacheManager() {
		List<Cache> caches = new ArrayList<>(this.cacheNames.size());
		for (String cacheName : this.cacheNames) {
			caches.add(clusterCache(cacheName));
		}

		SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
		simpleCacheManager.setCaches(caches);
		simpleCacheManager.afterPropertiesSet();
		return simpleCacheManager;
	}

	//...
}

この cacheManager が使われてしまうため、
こちらで用意した CacheManager が使われず Cannot find cache という問題が発生しました。

この "ElastiCacheCacheConfigurer" は、@EnableElastiCache アノテーションに import されているため、
@EnableElastiCache を使わなくても再現します。


解決方法

ElastiCache を使わない場合、
対策として、下記のような設定を追加して下さい。

@EnableAutoConfiguration(exclude = ElastiCacheAutoConfiguration.class) // ← ElastiCacheAutoConfiguration を除外する
@Configuration
@ComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

これで、自分の定義した cacheManager を使うようになります。