【问题标题】:Calling Spring Cacheable method within Cacheable method class cast exception在Cacheable方法类转换异常中调用Spring Cacheable方法
【发布时间】:2019-05-08 01:39:06
【问题描述】:

我正在尝试使用 Spring Cacheable,但遇到类转换异常

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CacheableTest.class, loader = AnnotationConfigContextLoader.class)
@Configuration
@EnableCaching
public class CacheableTest {
    public static final String CACHE = "cache";

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

    @Autowired
    DataService service;

    @Test
    public void cacheTest() {
        final String name = "name";
        Data a = service.getData(name);
        Data b = service.getData(new String(name));
        Assert.assertSame(a, b);
        String c = service.getValue(service.getData(name));
        String d = service.getValue(service.getData(new String(name)));
        Assert.assertSame(c, d);
        String e = service.getValue(name);
        String f = service.getValue(new String(name));
        Assert.assertSame(e, f);
    }

    public static class Data {
        private String value;
        public Data(String value) {
            this.value = value;
        }
    }

    @Service
    public static class DataService {
        @Resource
        private DataService self;

        @Cacheable(CACHE)
        public Data getData(String name) {
            return new Data(name);
        }

        @Cacheable(CACHE)
        public String getValue(Data data) {
            return data.value;
        }

        @Cacheable(CACHE)
        public String getValue(String name) {
            return self.getData(name).value;
        }
    }

}

异常说 CacheableTest$Data cannot be cast to java.lang.String 发生在字符串 e 行。我们知道为什么吗?

【问题讨论】:

    标签: java spring spring-cache


    【解决方案1】:

    您已经声明了 2 个具有相同参数但返回类型不同的方法。:

    public Data getData(String name)
    public String getValue(String name) 
    

    并且您将它们都标记为@Cacheable,具有相同的缓存名称CACHE。因此,您共享单个缓存来存储两种方法的结果。两种方法都具有完全相同的参数(String),因此 spring 为DataValue 计算的缓存键将发生冲突。

    第一个被调用的方法会返回 spring 放入缓存中的结果,第二个会尝试从缓存中检索相同的结果(因为缓存名称和方法参数匹配)并尝试将其转换为其他type - 因此,类转换异常。

    这和你这样做几乎是一样的:

    Map<String, Object> cache = new HashMap<>();
    cache.put("key", "value1");
    int i = (Integer)cache.get("key")
    

    【讨论】:

    • 嗯,好的。所以@Cacheable默认只检查输入参数来定位缓存的结果。感谢您回答“为什么”。你知道如何解决这个问题(例如将@Cacheable 组合为返回类型+方法名+输入参数作为唯一键来定位缓存)?
    • 我认为的解决方案是对不同类型使用单独的缓存。例如。您可以调用一个缓存"dataCache" 另一个"valueCache"。我想不出任何充分的理由将这两种类型的对象都保存在单个缓存中。至少这是我修复它的方式,它对我有用。您也可以制作自定义密钥生成器,但尚未这样做。
    • 说实话,我上面的回答实际上只是对正在发生的事情的最佳猜测。我遇到了同样的问题,因此找到了这个问题。我找不到任何关于 @Cacheable 如何在这个特定主题上工作的详细弹簧文档。如果有人可以指出它,我很乐意在我的答案中链接到它并在需要时进行修改。
    猜你喜欢
    • 2019-12-05
    • 1970-01-01
    • 2012-07-08
    • 2015-09-22
    • 2012-05-07
    • 1970-01-01
    • 2019-01-30
    • 1970-01-01
    • 2012-08-20
    相关资源
    最近更新 更多