2

我在scala-spring-cache建立了一个小测试项目来演示在 Scala 中使用ehcache-spring-annotations

为了使缓存起作用,必须使用方面。我有使用 CGLIB 或 AspectJ 的配置(或者可以添加@Scope(proxyMode = TARGET_CLASS)以获取仅用于该 bean 的代理)。

使用自动代理方面,当从类外部调用时,缓存可以正常工作。但是,当在类内部调用方法时,它会失败:

@Cacheable(cacheName = "thingy", decoratedCacheType = SELF_POPULATING_CACHE)
def expensive() = "bob"

def internallyCalling() = expensive()

在这里,来自类外部的调用expensive()将使用缓存,但调用internallyCalling()不会使用缓存。

我该如何解决这个问题,以便可以在内部使用缓存(如在 Java 中)?甚至可能吗?

4

2 回答 2

1

文档说

自调用

只有通过代理传入的外部方法调用才会被拦截。这意味着自调用,实际上是目标对象中的一个方法调用目标对象的另一个方法,即使调用的方法被标记为@Cacheable,在运行时也不会导致实际的缓存拦截。

顺便说一句,我不得不调整你的测试项目以满足 sbt。

这是用于比较的两个堆栈跟踪(低于规范2)。

外部拦截:

at com.github.fommil.cache.Thingy.expensive(Thingy.scala:20)
at com.github.fommil.cache.Thingy$$FastClassByCGLIB$$f58b1afb.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at com.googlecode.ehcache.annotations.resolver.ThreadLocalCacheEntryFactory.createEntry(ThreadLocalCacheEntryFactory.java:36)
at net.sf.ehcache.constructs.blocking.SelfPopulatingCache.get(SelfPopulatingCache.java:73)
at net.sf.ehcache.constructs.blocking.BlockingCache.get(BlockingCache.java:243)
at com.googlecode.ehcache.annotations.interceptor.EhCacheInterceptor.invokeSelfPopulatingCacheable(EhCacheInterceptor.java:174)
at com.googlecode.ehcache.annotations.interceptor.EhCacheInterceptor.invokeCacheable(EhCacheInterceptor.java:122)
at com.googlecode.ehcache.annotations.interceptor.EhCacheInterceptor.invoke(EhCacheInterceptor.java:81)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at com.github.fommil.cache.Thingy$$EnhancerByCGLIB$$d7d992e.expensive(<generated>)
at com.github.fommil.cache.Thingy$$FastClassByCGLIB$$f58b1afb.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:132)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at com.github.fommil.cache.Thingy$$EnhancerByCGLIB$$c2c26afd.expensive(<generated>)
at com.github.fommil.cache.ThingySpec$$anonfun$1$$anonfun$apply$5.apply(ThingySpec.scala:16)
at com.github.fommil.cache.ThingySpec$$anonfun$1$$anonfun$apply$5.apply(ThingySpec.scala:15)

...并在内部调用:

at com.github.fommil.cache.Thingy.expensive(Thingy.scala:20)
at com.github.fommil.cache.Thingy.internallyCalling(Thingy.scala:24)
at com.github.fommil.cache.Thingy$$FastClassByCGLIB$$f58b1afb.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:627)
at com.github.fommil.cache.Thingy$$EnhancerByCGLIB$$d7d992e.internallyCalling(<generated>)
at com.github.fommil.cache.Thingy$$FastClassByCGLIB$$f58b1afb.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:132)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at com.github.fommil.cache.Thingy$$EnhancerByCGLIB$$c2c26afd.internallyCalling(<generated>)
at com.github.fommil.cache.ThingySpec$$anonfun$1$$anonfun$apply$6.apply(ThingySpec.scala:22)
at com.github.fommil.cache.ThingySpec$$anonfun$1$$anonfun$apply$6.apply(ThingySpec.scala:21)

毫不奇怪,类似以下的工作:

import org.springframework.beans.factory.{ BeanFactory, BeanFactoryAware }

@Service
@Scope(proxyMode = TARGET_CLASS)
class Thingy extends JavaLogging with BeanFactoryAware {

  var called = 0

  @Cacheable(cacheName = "thingy", decoratedCacheType = SELF_POPULATING_CACHE)
  def expensive() = {
    called += 1
    Thread.sleep(1000)
    new Throwable().printStackTrace()
    "bob"
  }

  var myProxy: Thingy = _
  var myFactory: BeanFactory = _

  def setBeanFactory(beanFactory: BeanFactory): Unit = {
    myFactory = beanFactory
  }
  def internallyCalling() = {
    if (myProxy == null) myProxy = myFactory getBean classOf[Thingy]
    myProxy.expensive()
  }
}

只是为了确保没有本地检测正在进行,这可能取决于调用堆栈而被禁用,我通过调用伴随对象并返回来尝试它,并在将来包装它,但神奇的是代理.

于 2013-07-24T01:50:26.327 回答
0

这在 Scala 中似乎是不可能的。

于 2013-07-30T21:07:05.237 回答