Uso de la anotación de caché de primavera en varios módulos


Tengo un módulo util que produce un jar para ser utilizado en otras aplicaciones. Me gustaría que este módulo usara el almacenamiento en caché y preferiría usar el almacenamiento en caché de Spring annotation-driven.

Así que Util-Module tendría algo como esto:


DataManager.java

...
@Cacheable(cacheName="getDataCache")
public DataObject getData(String key) { ... }
...

Data-manager-ehcache.xml

...
<cache name="getDataCache" maxElementsInMemory="100" eternal="true" />
...

Data-manager-spring-config.xml

...
<cache:annotation-driven cache-manager="data-manager-cacheManager" />
<!-- ???? --->
<bean id="data-manager-cacheManager" 
    class="org.springframework.cache.ehcache.EhcacheCacheManager" 
    p:cache-manager="data-manager-ehcache"/>
<bean id="data-manager-ehcache" 
    class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" 
    p:config-location="data-manager-ehcache.xml"/>
...

También me gustaría que mi unidad desplegable tenga almacenamiento en caché a través de la anotación de primavera, mientras que incluyendo el tarro anterior como una dependencia. Así que mi Deployable-Unit tendría algo como esto:


MyApp.java

...
@Cacheable(cacheName="getMyAppObjectCache")
public MyAppObject getMyAppObject(String key) { ... }
...

My-app-ehcache.xml

...
<cache name="getMyAppObjectCache" maxElementsInMemory="100" eternal="true" />
...

My-app-spring-config.xml

...
<cache:annotation-driven cache-manager="my-app-cacheManager" />
<!-- ???? --->
<bean id="my-app-cacheManager" 
    class="org.springframework.cache.ehcache.EhcacheCacheManager" 
    p:cache-manager="my-app-ehcache"/>
<bean id="my-app-ehcache" 
    class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" 
    p:config-location="my-app-ehcache.xml"/>
...

Pregunta:

¿Es posible utilizar el almacenamiento en caché basado en anotaciones tanto en su proyecto principal como en un módulo de dependencias, manteniendo las configuraciones separadas?

Si no, se agradecería una explicación de por qué no lo es. Si es así, se agradecería una explicación de lo que necesita cambiar en la configuración anterior.

Author: Donal Fellows, 2011-12-28

5 answers

Esto parece estar fijado en 3. 2M1, véase https://jira.springsource.org/browse/SPR-8696

 9
Author: bgranvea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-03 09:42:47

Utilice esta clase: http://static.springsource.org/autorepo/docs/spring/3.2.0.M1/api/org/springframework/cache/support/CompositeCacheManager.html así:

<cache:annotation-driven cache-manager="cacheManager" />

<bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager">
    <property name="cacheManagers">
        <array>
            <ref bean="cacheManager1" />
            <ref bean="cacheManager2" />
        </array>
    </property>
    <property name="addNoOpCache" value="true" />
</bean>
 13
Author: Nicolas Mommaerts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-08 10:00:52

Spring espera actualmente que el CacheManager sea un Singleton. Esto es algo que el proyecto ehcache-spring-annotations se encontró y aún no he visto la solicitud cumplida. http://code.google.com/p/ehcache-spring-annotations/issues/detail?id=76

Al igual que con todas las cosas Java y Spring, tiene la opción de reimplementar la clase.

Http://forums.terracotta.org/forums/posts/list/5618.page#27960 proporciona una explicación básica de lo que algunas personas tienen proponer una solución y

Es el código real que se les ocurrió. El enfoque crea una convención a seguir, pero sería bastante fácil reimplementar esto con su propia versión si no le gusta el enfoque real descrito.

 5
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-20 17:23:08

En mi Proyecto he estado usando ABC jar dentro de XYZ war, ambos implementando ehCache con Spring 3.1,configuración basada en xml(tenemos ehCache.xml y luego spring-context.xml donde estamos interceptando caché a través de Spring AOP en ambos proyectos). Y estamos recibiendo el siguiente error:

java.lang.IllegalArgumentException: Cannot find cache named [xxxxxx] for CacheableOperation[] caches=[Cxxxxxxxx] | condition='' | key='#xxxxxxxxxxxxx' 
at org.springframework.cache.interceptor.CacheAspectSupport.getCaches(CacheAspectSupport.java:163) [spring-context-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContext.<init>(CacheAspectSupport.java:443) [spring-context-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.cache.interceptor.CacheAspectSupport.getOperationContext(CacheAspectSupport.java:173) [spring-context-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.cache.interceptor.CacheAspectSupport.createOperationContext(CacheAspectSupport.java:404) [spring-context-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:192) [spring-context-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:66) [spring-context-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at com.infy.flypp.dao.ContentDAO$$EnhancerByCGLIB$$9443481.getContentById(<generated>) [cglib-2.2.2.jar:] 

Solución:

Así es como resolvimos este problema:

  1. Hemos copiado toda la configuración de caché de ABCehCache.xml (desde ABC jar) a XYZehCache.xml (de la guerra XYZ).
  2. Eliminamos el ABCehCache.xml (de ABC jar) pero toda la configuración(como la instanciación de bean para ehCache.xml y Spring AOP) dentro de ABC-spring.xml seguirá siendo la misma.
  3. En XYZ-spring.xml, importamos ABC-spring.xml y definimos el administrador de caché compuesto.

Archivos de configuración soportados:

ABC-spring.xml:

    <aop:aspectj-autoproxy proxy-target-class="true" />

    <bean id="CacheManager1" class="org.springframework.cache.ehcache.EhCacheCacheManager">
        <property name="cacheManager" ref="ehcache"></property>
    </bean>

    <bean id="ehcache"
        class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
        p:config-location="classpath:ABCEhcache.xml" />

XYZ-spring.xml:

<import resource="classpath*:ABC-spring.xml" />
<aop:aspectj-autoproxy proxy-target-class="true" />

    <bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager">
    <property name="cacheManagers">
        <array>
            <ref bean="CacheManager1" />
            <ref bean="CacheManager2" />
        </array>
    </property>
    <property name="fallbackToNoOpCache" value="true" />
</bean>

    <bean id="CacheManager2" class="org.springframework.cache.ehcache.EhCacheCacheManager"
        p:cache-manager-ref="ehcache" />
    <bean id="ehcache"
        class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
        p:config-location="classpath:XYZEhcache.xml" />
 2
Author: ritesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-05 07:55:53

Consideraría las siguientes alternativas mucho más simples:

  1. Opción 1: Anote sus métodos cacheable en el módulo de utilidad con @Cacheable, pero deje que la aplicación que los encierra cree y configure los cachés. En su ejemplo, declararía y configuraría una caché 'getDataCache' en el módulo de la aplicación, aunque la caché se use en la anotación de una clase que reside en el módulo de utilidad.
  2. Opción 2: deje que el módulo de utilidad cree la configuración de la caché, pero no la caché gerente en sí. El módulo de aplicación combinaría las configuraciones de caché de los módulos de utilidad y la propia aplicación para crear un solo administrador de caché.

No me gustó la solución de CompositeCacheManager, ya que su comportamiento es muy dependiente de la implementación de cachés subyacentes: solo funcionará como se espera si todos los administradores de caché subyacentes devuelven null en nombre de caché desconocido. Algunas implementaciones los crearían sobre la marcha, dando como resultado cachés con configuración eso no lo esperabas.

 1
Author: Alexander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-27 15:32:57