ejemplo - Spring 3.1 @Cacheable-método aún ejecutado
spring cache service (3)
Estoy tratando de implementar el almacenamiento en memoria caché de Spring 3.1 como se explica here y here , pero no parece estar funcionando: mi método se ejecuta a través de todas las veces a pesar de que está marcado @cacheable. ¿Qué estoy haciendo mal?
Lo he trasladado a un caso de prueba junit con su propio archivo de configuración para aislarlo del resto de mi aplicación, pero el problema todavía ocurre. Aquí están los archivos relevantes:
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;
}
}
Entradas relevantes de 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>
cuando ejecuto la prueba, Spring saca algunos mensajes de depuración que parecen que mi caché se inicializó sin errores
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''.
pero el resultado de la depuración no muestra comprobaciones de caché entre las llamadas a métodos de algún Método y la instrucción de impresión desde el interior de algún Método imprime todo el tiempo.
¿Se me escapa algo?
Además de Lee Chee Kiam: Aquí está mi solución para pequeños proyectos con solo el uso marginal de llamadas de método de anulación (no anotadas). El DAO simplemente se inyecta en sí mismo como un proxy y llama a sus propios métodos utilizando ese proxy en lugar de una simple llamada a método. Entonces @Cacheable se considera sin hacer una complicada insturmentación.
La documentación dentro del código es altamente recomendada, ya que puede parecer extraño para los colegas. Pero es fácil de probar, simple, rápido de lograr y me ahorra la instrumentación AspectJ completa. Sin embargo, para un uso más intenso también aconsejaría la solución AspectJ como lo hizo Lee Chee Kiam.
@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;
}
}
De http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/cache.html
En el modo proxy (que es el predeterminado), solo se interceptan las llamadas a métodos externos que ingresan a través del proxy. Esto significa que la auto invocación, en efecto, un método dentro del objeto objetivo que llama a otro método del objeto objetivo , no conducirá a un almacenamiento en caché real en el tiempo de ejecución incluso si el método invocado está marcado con @Cacheable, considerando usar el modo aspectj en este caso.
y
Visibilidad del método y
@Cacheable
/@CachePut
/@CacheEvict
Al usar proxies, debe aplicar las anotaciones
@Cache
solo a los métodos con visibilidad pública .
- Usted
someMethod
en el mismo objeto de destino. - Su método
@Cacheable
no es público.
Debe definir un caché que coincida con el nombre al que hace referencia en su anotación ("método de prueba"). Cree una entrada en su ehcache.xml para ese caché también.