当前位置: 首页 > 知识库问答 >
问题:

Spring缓存不工作w/nested方法

裘嘉木
2023-03-14

我有一个方法可以调用另一个@Cacheable方法,如下所示:

public ItemDO findMethod2(long itemId) {
    this.findMethod1(itemId);
    ...
}

@Cacheable(value = "Item", key="#itemId", unless="#result == null")
public ItemDO findMethod1(long itemId) {
    ...
}

如果我直接调用findomeod1(),缓存工作得很好。但是,当我调用findomeod2()时,findomeod1()上的缓存被完全忽略。

这可能是JVM将findMethod1()内联到findMethod2()中的伎俩吗?

有没有人遇到过类似的问题?

谢谢

共有2个答案

昝浩阔
2023-03-14

我发现其他方便的解决方案是使用@资源,然后调用目标(在您的情况下是方法1),使用该资源引用https://stackoverflow.com/a/48867068/2488286

梁丘弘
2023-03-14

这不是JVM的把戏,也就是说,findMethod1()没有被内联到findMethod2()或任何类似的东西中。

问题在于,您的代码绕过了Spring为@Cacheable注释围绕应用程序类(包含findMethod1())创建的“代理”。

与Spring的事务注释和底层架构体系一样,给定一个接口,默认情况下Spring将创建一个JDK动态代理(AOP风格)来“拦截”方法调用并应用“建议”(由注释类型决定,在本例中是缓存)。然而,一旦从代表目标对象的拦截器(代理)调用目标对象来应用建议,线程现在就会在目标对象的上下文中执行,因此来自目标对象内部的任何后续方法调用都将直接发生在目标对象本身上。

看起来有点像这样。。。

caller -> Proxy -> findMethod2() -> findMethod1()

理想情况下你想要的是。。。

caller -> Proxy -> findMethod2() -> Proxy -> findMethod1()

然而,一旦进入findMethod2()线程就已经在“target”对象的上下文中执行了,因此您将得到第一个调用堆栈。

Spring医生在这里解释得更好。

该文档接着指出了解决这个问题的方法,最有利的方法是重构代码,以确保调用者通过代理拦截器进行第二次方法调用(即findomeod1())。

我还收集了另一个解决这个问题的方法,即使用全面的AspectJ,在应用程序构建过程中使用编译器和字节码编织器来修改实际的目标对象,以便来自目标对象内部的后续调用拦截并相应地应用建议。

有关Spring AOP和完整的AspectJ之间的权衡,以及如何在Spring应用程序中使用完整的AspectJ,请参阅Spring文档。

希望这有帮助。

干杯

 类似资料:
  • 我使用Spring缓存抽象使用Ehache作为缓存提供程序。我试图将缓存操作附加到Spring JPA事务,但无法这样做。 即使事务失败/回滚缓存放发生。 配置, springcache-abs-ehcache。xml, 雇员安置处, 事务方法, 测试用例(调用者), 测试应该成功,也就是说,如果事务在该方法中回滚,Spring不应该将数据放入方法中的缓存中。但是,即使事务失败,Spring也会将

  • 我正在建立一个“类缓存”,我想稍后调用类。 主要的目标是,我不希望每次需要类实例时都扫描上下文。 首先要评估缓存,我将缓存方法@AutoWired放在@RestController中,这会很好地工作。在调用rest方法时填充缓存。 完成之后,我将@AutoWired对象移动到@Service中,创建一个方法来自填充缓存。但这不起作用。调用@PostConstructor方法时不填充缓存。 如何使用

  • 它的灵感来自spring-data-jpa-examples/src/main/resources/caching-repository-context.xml 看日志;每次请求时,我都会看到查询被执行。 下次我请求时,我看到以下查询;

  • 我想将主数据缓存到Redis。 所以,我写了这些代码。 和 和ymlfile 但是,缓存不工作... 无论何时调用printTest方法,都将执行“getTest”方法。Redis没有数据。。。我的代码中有什么问题? SpringBoot版本是1.4.0 依赖关系是

  • 在我的项目中,我使用了一个@Cacheable注释ia一个服务方法,它返回涉及书籍和一些标记的计算结果,我想在一个@Controller类方法中退出缓存,该方法将一本新书添加到数据库中,因为这本新书将是新计算所必需的。 服务类:@Cacheable("metas") 控制器类:@RequestMapping@CacheEvict(value=“metas”,allEntries=true)

  • 我已经使用咖啡因缓存设置了一个场景,但我无法让它工作,当参数相同时,总是调用真正的方法。这是我的配置: 波姆。xml CacheManager的配置类 然后是具有可缓存方法的类: 我还尝试将缓存名称添加到可缓存批注: 并将移动到Spring Boot主应用程序类。 真正的方法总是被调用的。 你知道我做错了什么吗? 谢谢