Spring 3.1 @Cacheable - 方法仍然执行

时间:2012-04-27 02:07:24

标签: spring caching ehcache

我正在尝试按照herehere解释实现Spring 3.1缓存,但它似乎不起作用:我的方法每次都会运行,即使它被标记为@cacheable 。我做错了什么?

我已将其移入带有自己的配置文件的junit测试用例,以将其与我的应用程序的其余部分隔离,但问题仍然存在。以下是相关文件:

弹簧测试servlet.xml中

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:cache="http://www.springframework.org/schema/cache"
   xmlns:p="http://www.springframework.org/schema/p"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<cache:annotation-driven />

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
      p:config-location="classpath:ehcache.xml"/>
</beans>

ehcache.xml中

<ehcache>
<diskStore path="java.io.tmpdir"/>
<cache name="cache"
       maxElementsInMemory="100"
       eternal="false"
       timeToIdleSeconds="120"
       timeToLiveSeconds="120"
       overflowToDisk="true"
       maxElementsOnDisk="10000000"
       diskPersistent="false"
       diskExpiryThreadIntervalSeconds="120"
       memoryStoreEvictionPolicy="LRU"/>

</ehcache>

MyTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring-test-servlet.xml"})
@Component
public class MyTest extends TestCase {

    @Test
    public void testCache1(){
        for(int i = 0; i < 5; i++){
            System.out.println("Calling someMethod...");
            System.out.println(someMethod(0));
        }
    }

    @Cacheable("testmethod")
    private int someMethod(int val){
        System.out.println("Not from cache");
        return 5;
    }
}

相关Pom条目:(spring-version = 3.1.1.RELEASE)

    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache-core</artifactId>
        <version>2.5.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring.version}</version>
    </dependency>

当我运行测试时,Spring会发出一些调试消息,看起来我的缓存初始化没有错误

DEBUG: config.ConfigurationHelper - No CacheManagerEventListenerFactory class specified. Skipping...
DEBUG: ehcache.Cache - No BootstrapCacheLoaderFactory class specified. Skipping...
DEBUG: ehcache.Cache - CacheWriter factory not configured. Skipping...
DEBUG: config.ConfigurationHelper - No CacheExceptionHandlerFactory class specified. Skipping...
DEBUG: store.MemoryStore - Initialized net.sf.ehcache.store.MemoryStore for cache
DEBUG: disk.DiskStorageFactory - Failed to delete file cache.data
DEBUG: disk.DiskStorageFactory - Failed to delete file cache.index
DEBUG: disk.DiskStorageFactory - Matching data file missing (or empty) for index file. Deleting index file /var/folders/qg/xwdvsg6x3mx_z_rcfvq7lc0m0000gn/T/cache.index
DEBUG: disk.DiskStorageFactory - Failed to delete file cache.index
DEBUG: ehcache.Cache - Initialised cache: cache
DEBUG: config.ConfigurationHelper - CacheDecoratorFactory not configured. Skipping for 'cache'.
DEBUG: config.ConfigurationHelper - CacheDecoratorFactory not configured for defaultCache. Skipping for 'cache'.

但是调试输出显示对someMethod的方法调用和someMethod内部的print语句之间没有缓存检查。

我有什么遗失的吗?

3 个答案:

答案 0 :(得分:80)

来自http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/cache.html

  

在代理模式(默认设置)下,只有外部方法调用   通过代理进入是截获的。这意味着   自调用,实际上是目标对象调用中的一个方法   目标对象的另一种方法不会导致实际   在运行时缓存,即使调用的方法被标记   @Cacheable - 考虑在这种情况下使用aspectj模式。

  

方法可见性和@Cacheable / @CachePut / @CacheEvict

     

使用代理时,您应该仅应用@Cache注释   具有公众可见度的方法。

  1. 您在同一目标对象中自我调用someMethod
  2. 您的@Cacheable方法不公开。

答案 1 :(得分:2)

您需要定义一个与您在注释中引用的名称匹配的缓存(“testmethod”)。在ehcache.xml中为该缓存创建一个条目。

答案 2 :(得分:1)

除了Lee Chee Kiam:这是我的小型项目的解决方案,只有边际使用绕过(未注释)的方法调用。 DAO只是作为代理注入其自身,并使用该代理调用它自己的方法而不是简单的方法调用。因此考虑@Cacheable而不进行复杂的操作。

强烈建议使用代码内文档,因为对同事来说可能看起来很奇怪。但它易于测试,简单,快速实现,并使我完全成熟的AspectJ仪器。然而,对于更重的用法,我也会像Lee Chee Kiam那样建议AspectJ解决方案。

@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {

    private final PersonDao _personDao;

    @Autowired
    public PersonDao(PersonDao personDao) {
        _personDao = personDao;
    }

    @Cacheable(value = "defaultCache", key = "#id")
    public Person findPerson(int id) {
        return getSession().getPerson(id);
    }

    public List<Person> findPersons(int[] ids) {
        List<Person> list = new ArrayList<Person>();
        for (int id : ids) {
            list.add(_personDao.findPerson(id));
        }
        return list;
    }
}