@Cacheable注解在无参数方法上的应用

30

我想在没有参数的方法上使用@Cacheable注解。在这种情况下,我会按如下方式使用@Cacheable

@Cacheable(value="usercache", key = "mykey")
public string sayHello(){
    return "test"
}
然而,当我调用这个方法时,它没有被执行,并且出现了以下异常。

org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'mykey' cannot be found on object of type 'org.springframework.cache.interceptor.CacheExpressionRootObject' - maybe not public?

请建议。
5个回答

54

似乎Spring不允许您在中提供静态文本用作缓存键,并且默认情况下不包括方法名称作为键,因此,在没有键的情况下,使用相同的两个方法可能会将不同的结果缓存到相同的键中。

最简单的解决方法是将方法名称作为键提供:

@Cacheable(value="usercache", key = "#root.methodName")
public string sayHello(){
return "test"
}

这将设置sayHello作为键。

如果您确实需要静态键,应该在类中定义一个静态变量,并使用#root.target

public static final String MY_KEY = "mykey";

@Cacheable(value="usercache", key = "#root.target.MY_KEY")
public string sayHello(){
return "test"
}
你可以在这里找到可用于键中的SPEL表达式列表。 here

1
请问您能解释一下这行代码吗?在您的情况下,静态密钥(mykey)也没有意义,因为Spring已将缓存绑定到特定方法。那么如果我没有明确指定,将会存储哪个键值到缓存中呢? - user3534483
1
@user3534483 抱歉,我之前关于Spring使用的默认键的说法是错误的。我已经编辑了答案并添加了正确的信息。 - Ruben
1
似乎Spring不允许您在SPEL中为缓存键提供静态文本。这是错误的,因为您可以使用字符串字面量。例如,我在生产中使用private static final String CACHE_KEY_ALL = "'##all'";,它非常有效。无论如何,答案很好,所以我不会给它负评。 - usr-local-ΕΨΗΕΛΩΝ
@Ruben 为什么无需参数的方法需要键值?我可以使用 #1 @Cachable("cache1") method1() #2 @Cachable("cache2") method2()。这样做是不正确的吗? - StackOverFlow
这是一个部分正确,部分不正确的答案。请查看Clif下面的答案。那应该是被接受的答案。 - Michael Rountree

47

尝试在mykey周围添加单引号。 这是SPEL表达式,单引号使其重新变为String

@Cacheable(value="usercache", key = "'mykey'")

3
这应该是正确的答案,因为它完全正确并直接回答了问题。 - Michael Rountree
这是通常每个Java开发者都会忽略的事情,即添加单引号。 - undefined

2
你可以省略key参数。Spring会将带有SimpleKey.EMPTY键的值放入缓存中:
@Cacheable("usercache")

除了使用其他解决方案中概述的 SPEL 之外,您始终可以注入 CacheManager 并手动处理它。

如何解决单元测试中的问题? https://dev59.com/eavka4cB1Zd3GeqPwafW - Gowrav
@Gowrav 或许是 Mockito 在干扰? - Terran
似乎是这样,我无法解决。如果API有参数,则它按预期工作,但没有参数则出现相同的问题。也许我们应该在Mockito上记录一个错误。 - Gowrav
@Gowrav 尝试使用 doReturn(...).when(...)。有时候这样重新排序可以帮助Mockito正常工作。 - Terran

0

对我来说,问题在于键的语法不正确。

@Cacheable(value = "name", key = "#object.field1+object.field2")

正确的做法是在关键项前加上 # 符号:

@Cacheable(value = "name", key = "#object.field1+#object.field2")

-2
在键中添加 # 符号
@Cacheable(value="usercache", key = "#mykey")
public string sayHello(){
    return "test"
}

这是用于变量替换的,如果 #mykey 是某个已定义的变量。然而,它并没有被定义,因此会导致空键错误。 - Michael Rountree

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接