这不是 JVM 技巧,即findMethod1()
没有被内联findMethod2()
或任何类似性质的东西。
问题是您的代码绕过了Spring围绕您的应用程序类(包含findMethod1()
)为@Cacheable
注释创建的“代理”。
像Spring 的事务注解和底层基础设施一样,给定一个接口,默认情况下Spring将创建一个 JDK 动态代理(AOP 样式)来“拦截”方法调用并应用“建议”(由注解的类型决定,在这种情况下,缓存)。但是,一旦从代表目标对象的拦截器(代理)调用目标对象以应用建议,线程现在正在目标对象的上下文中执行,因此来自目标对象内的任何后续方法调用都会发生直接作用于目标对象本身。
它看起来有点像这样......
caller -> Proxy -> findMethod2() -> findMethod1()
理想情况下,你想要的是这个......
caller -> Proxy -> findMethod2() -> Proxy -> findMethod1()
但是,线程已经在“目标”对象的上下文中执行findMethod2()
,因此您最终会得到第一个调用堆栈。
Spring 文档在这里更好地解释了它。
该文档继续指出了该问题的解决方案,最有利的是重构您的代码,以确保调用者通过代理拦截器进行第二次方法调用(即findMethod1()
)。
我还收集到这个问题的另一个解决方案是使用完整的AspectJ
,在应用程序构建过程中使用编译器和字节码编织器来修改实际的目标对象,以便目标对象内的后续调用拦截并相应地应用建议.
请参阅 Spring 文档,了解与 full之间的权衡,以及如何在 Spring 应用程序中使用 full AspectJ。Spring AOP
AspectJ
希望这可以帮助。
干杯!