2012-04-27 3 views
25

Я пытаюсь реализовать кэширование Spring 3.1, как описано here и here, но он, похоже, не работает: мой метод запускается каждый раз, хотя он отмечен как @cacheable , Что я делаю не так?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: (весна -версия = 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> 

, когда я запустить тест, весна ставит некоторые отладочные сообщения, которые выглядят как мой кэш инициализируются без ошибок

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 печатает каждый раз.

Есть ли что-то, что мне не хватает?

ответ

76

От 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 метод не является общедоступным.
+0

В дополнение к этому, вам нужно для извлечения в интерфейс, поэтому Spring может динамически писать оболочку в ваш класс. – RockMeetHardplace

2

Вам необходимо определить кеш, который соответствует имени, которое вы указали в аннотации («testmethod»). Создайте запись в вашем ehcache.xml для этого кеша.

+0

Это был также вопрос с моим оригинальным кодом, который стал очевидным, когда я назвал метод таким образом, что пытался поставить его в кэше (см общепринятое решение) –

1

В дополнение к Lee Chee Kiam: Вот мое решение для небольших проектов с ограниченным использованием обходных (не аннотированных) вызовов метода. DAO просто вводится в себя как прокси-сервер и называет его собственными методами, используя этот прокси вместо простого вызова метода. Так что @Cacheable считается без сложной инсталляции.

Внутрикодовая документация настоятельно рекомендуется, так как это может показаться странным для коллег. Но его легко проверить, просто, быстро достичь и избавит меня от полномасштабного инструментария AspectJ. Однако для более интенсивного использования я также посоветовал решение 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; 
    } 
} 
+0

это просто аннотация @Scope, которая обходит режим прокси-сервера? У меня есть аналогичный вопрос здесь http://stackoverflow.com/questions/36486620/correct-key-annotation-for-caching-on-items-in-a-list-rather-then-the-whole-list –

+0

I ' Извините, я думаю, что я не понял вопроса правильно. Я не вижу связи с вашим сообщением. –

+0

«обход» в этом контексте означает, что метод не аннотируется с помощью @Cachable, но он использует встроенные методы внедренного прокси внутри, WHICH, в свою очередь, является прокси-сервером «this» itslef. Kinda freaky;) Объект вводится в себя как прокси-сервер, чтобы избежать сложной инсталляции. –

Смежные вопросы