【问题标题】:Spring Cache a List of object with Condition getting IllegalArgumentExceptionSpring缓存条件获取IllegalArgumentException的对象列表
【发布时间】:2015-11-19 17:05:28
【问题描述】:

我想在级别 == 0 时缓存类别列表,但不断收到 IllegalArgumentException。我错过了什么?

在服务类中:

@Override
@Transactional(readOnly = true)
@Cacheable(value="categories", condition="#level == 0")
public List<Category> findCategoryByLevel(int level) throws DataAccessException {
    return categoryRepository.findCategoryByLevel(level);
}

错误:

java.lang.IllegalArgumentException: Cannot find cache named 'categories' for CacheableOperation[public java.util.List com.mySite.service.DidicityServiceImpl.findCategoryByLevel(int) throws org.springframework.dao.DataAccessException] caches=[categories] | key='' | condition='#level == 0' | unless=''

【问题讨论】:

    标签: spring caching spring-cache


    【解决方案1】:

    您在Spring 的缓存抽象 中使用了什么缓存提供程序? (即 ehcache、Guava、Hazelcast 等)

    您的实际缓存提供程序中似乎缺少明确的“Cache”定义和实例。例如,当在Spring's Cache Abstraction 中使用Pivotal GemFire 作为caching provider 时,您需要在Spring Cache Abstraction 中定义一个Region(又名Cache),使用上面的示例,就这样……

    <gfe:cache ...>
    
    <gfe:replicated-region id="categories" persistent="false"...>
      ...
    </gfe:replicated-region>
    

    Spring Data GemFire 在调用缓存的应用程序服务|存储库方法时进入lookupCache”,因此实际支持“Cache”(即GemFire 区域)必须存在,否则 Spring Cache Abstraction throws an IllegalArgumentException.

    因此,通过一个更明确的示例,我编写了以下测试...

    /*
     * Copyright 2014-present the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *        http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.spring.cache;
    
    import static org.hamcrest.CoreMatchers.*;
    import static org.junit.Assert.*;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.spring.cache.CachingWithConcurrentMapUsingExplicitlyNamedCachesTest.ApplicationConfiguration;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.stereotype.Service;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    /**
     * The CachingWithConcurrentMapUsingExplicitlyNamedCachesTest class is a test suite of test cases testing the contract
     * and functionality of Spring Cache Abstraction using the ConcurrentMap-based Cache Management Strategy 
     * with explicitly named "Caches".
     * 
     * NOTE: when the Cache(s) [is|are] explicitly named using the ConcurrentMapCacheManager, then "dynamic" is disabled
     * and corresponding the named Cache in the @Cacheable annotation of the cached service method must exist 
     * (or be declared).  If no explicitly named Caches are provided to the ConcurrentMapManager constructor, then dynamic
     * is enabled and the Cache will be created at runtime, on the fly.
     *
     * @author John Blum
     * @see org.junit.Test
     * @see org.junit.runner.RunWith
     * @see org.springframework.cache.Cache
     * @see org.springframework.cache.CacheManager
     * @see org.springframework.cache.annotation.Cacheable
     * @see org.springframework.cache.annotation.EnableCaching
     * @see org.springframework.cache.concurrent.ConcurrentMapCacheManager
     * @see org.springframework.context.annotation.Bean
     * @see org.springframework.context.annotation.Configuration
     * @see org.springframework.test.context.ContextConfiguration
     * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
     * @since 1.0.0
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = ApplicationConfiguration.class)
    @SuppressWarnings("unused")
    public class CachingWithConcurrentMapUsingExplicitlyNamedCachesTest {
    
      @Autowired
      private NumberCategoryService numberCategoryService;
    
      @Test
      public void numberCategoryCaching() {
        assertThat(numberCategoryService.isCacheMiss(), is(false));
    
        List<NumberCategory> twoCategories = numberCategoryService.classify(2.0);
    
        assertThat(twoCategories, is(notNullValue()));
        assertThat(twoCategories.size(), is(equalTo(3)));
        assertThat(twoCategories.containsAll(Arrays.asList(
          NumberCategory.EVEN, NumberCategory.POSITIVE, NumberCategory.WHOLE)), is(true));
        assertThat(numberCategoryService.isCacheMiss(), is(true));
    
        List<NumberCategory> twoCategoriesAgain = numberCategoryService.classify(2.0);
    
        assertThat(twoCategoriesAgain, is(sameInstance(twoCategories)));
        assertThat(numberCategoryService.isCacheMiss(), is(false));
    
        List<NumberCategory> negativeThreePointFiveCategories = numberCategoryService.classify(-3.5);
    
        assertThat(negativeThreePointFiveCategories, is(notNullValue()));
        assertThat(negativeThreePointFiveCategories.size(), is(equalTo(3)));
        assertThat(negativeThreePointFiveCategories.containsAll(Arrays.asList(
          NumberCategory.ODD, NumberCategory.NEGATIVE, NumberCategory.FLOATING)), is(true));
        assertThat(numberCategoryService.isCacheMiss(), is(true));
      }
    
      @Configuration
      @EnableCaching
      public static class ApplicationConfiguration {
    
        @Bean
        public CacheManager cacheManager() {
          //return new ConcurrentMapCacheManager("Categories");
          return new ConcurrentMapCacheManager("Temporary");
        }
    
        @Bean
        public NumberCategoryService numberCategoryService() {
          return new NumberCategoryService();
        }
      }
    
      @Service
      public static class NumberCategoryService {
    
        private volatile boolean cacheMiss;
    
        public boolean isCacheMiss() {
          boolean localCacheMiss = this.cacheMiss;
          this.cacheMiss = false;
          return localCacheMiss;
        }
    
        protected void setCacheMiss() {
          this.cacheMiss = true;
        }
    
        @Cacheable("Categories")
        public List<NumberCategory> classify(double number) {
          setCacheMiss();
    
          List<NumberCategory> categories = new ArrayList<>(3);
    
          categories.add(isEven(number) ? NumberCategory.EVEN : NumberCategory.ODD);
          categories.add(isPositive(number) ? NumberCategory.POSITIVE : NumberCategory.NEGATIVE);
          categories.add(isWhole(number) ? NumberCategory.WHOLE : NumberCategory.FLOATING);
    
          return categories;
        }
    
        protected boolean isEven(double number) {
          return (isWhole(number) && Math.abs(number) % 2 == 0);
        }
    
        protected boolean isFloating(double number) {
          return !isWhole(number);
        }
    
        protected boolean isNegative(double number) {
          return (number < 0);
        }
    
        protected boolean isOdd(double number) {
          return !isEven(number);
        }
    
        protected boolean isPositive(double number) {
          return (number > 0);
        }
    
        protected boolean isWhole(double number) {
          return (number == Math.floor(number));
        }
      }
    
      public enum NumberCategory {
        EVEN,
        FLOATING,
        NEGATIVE,
        ODD,
        POSITIVE,
        WHOLE
      }
    
    }
    

    此测试示例当前设置为抛出 IllegalArgumentException。如果你改变这个......

    return new ConcurrentMapCacheManager("Temporary");
    

    到这里……

    return new ConcurrentMapCacheManager("Categories");
    

    那么一切都很好。

    希望这足以说明您遇到的问题以及如何解决它。

    干杯, 约翰

    【讨论】:

      【解决方案2】:

      看起来您想将密钥用作静态硬编码字符串。 试试下面的“‘类别’”

      @Override
      @Transactional(readOnly = true)
      @Cacheable(value="'categories'", condition="#level == 0")
      public List<Category> findCategoryByLevel(int level) throws DataAccessException {
          return categoryRepository.findCategoryByLevel(level);
      } 
      

      【讨论】:

        猜你喜欢
        • 2016-02-21
        • 1970-01-01
        • 2018-06-19
        • 1970-01-01
        • 2012-12-31
        • 1970-01-01
        • 2018-12-19
        • 2018-09-19
        • 2015-09-25
        相关资源
        最近更新 更多