我有一个方法来调用另一个@Cacheable方法,如下所示:
public ItemDO findMethod2(long itemId) {
this.findMethod1(itemId);
...
}
@Cacheable(value = "Item", key="#itemId", unless="#result == null")
public ItemDO findMethod1(long itemId) {
...
}
Run Code Online (Sandbox Code Playgroud)
如果我直接调用findMethod1(),缓存效果很好.但是,当我调用findMethod2()时,findMethod1()上的缓存完全被忽略.
这可能是JVM将findMethod1()内联到findMethod2()中的伎俩吗?
有没有人遇到类似的问题?
谢谢!
这不是JVM技巧,即findMethod1()内部没有内联findMethod2()或者那种性质.
问题是你的代码绕过了Spring在你的应用程序类(包含findMethod1())中为@Cacheable注释创建的"代理" .
与Spring的 Transactional注释和底层基础结构一样,给定一个接口,默认情况下Spring会创建一个JDK动态代理(AOP样式)来"拦截"方法调用并应用"建议"(由注释类型决定,在这种情况下) ,缓存).但是,一旦从代表目标对象的拦截器(代理)调用目标对象以应用建议,则线程现在在目标对象的上下文中执行,因此目标对象内的任何后续方法调用都在发生直接在目标对象本身上.
它看起来像这样......
caller -> Proxy -> findMethod2() -> findMethod1()
Run Code Online (Sandbox Code Playgroud)
理想情况下你想要的是......
caller -> Proxy -> findMethod2() -> Proxy -> findMethod1()
Run Code Online (Sandbox Code Playgroud)
但是,一旦进入内部findMethod2(),Thread已经在"target"对象的上下文中执行,因此您最终得到了第一个调用堆栈.
Spring文档在这里解释得更好.
该文档继续指出这个问题的解决方案,最有利的是重构代码以确保调用者通过代理拦截器进行第二个方法调用(即findMethod1()).
我还收集另一个解决这个问题的方法就是AspectJ在应用程序构建过程中使用编译器和字节码编织器来完成,修改实际的目标对象,以便后续的调用从目标对象内部拦截并相应地应用建议.
看到在春节文档取舍之间Spring AOP和充分AspectJ,以及如何使用完整的AspectJ的Spring应用程序.
希望这可以帮助.
干杯!
| 归档时间: |
|
| 查看次数: |
781 次 |
| 最近记录: |