【问题标题】:Spring 3.1 @Cacheable - method still executedSpring 3.1 @Cacheable - 方法仍然执行
【发布时间】:2012-05-07 19:17:01
【问题描述】:

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

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

Spring-test-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 语句之间没有缓存检查。

我有什么遗漏吗?

【问题讨论】:

    标签: spring caching ehcache


    【解决方案1】:

    来自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 方法未公开。

    【讨论】:

    • 除此之外,您还需要提取到接口,以便 Spring 可以动态地将包装器写入您的类。
    【解决方案2】:

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

    【讨论】:

    • 这也是我的原始代码的一个问题,一旦我以试图将其放入缓存的方式调用该方法(请参阅已接受的解决方案)
    【解决方案3】:

    除了 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;
        }
    }
    

    【讨论】:

    • 它只是绕过代理模式的@Scope注释吗?我在这里有一个类似的问题stackoverflow.com/questions/36486620/…
    • 对不起,我想我没有回答正确的问题。我没有看到与您的帖子的联系。
    • "bypassing" 在该上下文中意味着,该方法没有使用 @Cachable 注释,但它在内部使用注入代理的 chached 方法,而这又是“this”本身的代理。有点怪异 ;) 该对象作为代理被注入自身以避免复杂的仪器。
    • 这是一个有趣的 hack,但我对如何构造这样的对象感到困惑。
    • 通过 ScopedProxyMode.TARGET_CLASS 的魔力构建。 Spring 制作了一个在使用之前不会解析的代理。当此类访问代理时,代理被解析为对底层对象的引用。但是 Spring 也可以使用缓存包装器包装代理以使其可缓存。
    猜你喜欢
    • 2012-08-07
    • 2012-12-25
    • 2011-12-20
    • 2019-01-30
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    • 2019-05-08
    • 1970-01-01
    相关资源
    最近更新 更多