Использование аннотации кеша Spring в нескольких модулях - PullRequest
31 голосов
/ 28 декабря 2011

У меня есть модуль утилит, который создает банку для использования в других приложениях. Я хотел бы, чтобы этот модуль использовал кэширование и предпочел бы использовать annotation-driven кэширование Spring.

Так что Util-Module будет выглядеть примерно так:


DataManager.java

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

Данные-менеджер-ehcache.xml

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

Данные-менеджер-весна-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"/>
...

Мне также хотелось бы, чтобы у моего развертываемого модуля было кеширование с помощью аннотации Spring, при этом в качестве зависимости использовался вышеуказанный jar. Так что мой Deployable-Unit будет выглядеть примерно так:


MyApp.java

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

мой-приложение-ehcache.xml

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

мой-приложение-весна-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"/>
...

Вопрос:

Можно ли использовать кеширование на основе аннотаций как в основном проекте, так и в модуле зависимостей, сохраняя конфигурации раздельными?

Если нет, то объяснение, почему это не так, будет оценено. Если это так, было бы желательно получить пояснение того, что необходимо изменить в вышеупомянутой конфигурации.

Ответы [ 5 ]

13 голосов
/ 08 февраля 2012

Используйте этот класс: http://static.springsource.org/autorepo/docs/spring/3.2.0.M1/api/org/springframework/cache/support/CompositeCacheManager.html как это:

<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>
9 голосов
/ 03 февраля 2012

это, кажется, исправлено в 3.2M1, см. https://jira.springsource.org/browse/SPR-8696

5 голосов
/ 20 января 2012

Spring в настоящее время ожидает, что cacheManager будет Singleton. Это то, с чем столкнулся проект ehcache-spring-annotations, и я пока не вижу, что запрос выполнен. http://code.google.com/p/ehcache-spring-annotations/issues/detail?id=76

Как и во всех вещах Java и Spring, у вас есть возможность переопределить класс.

http://forums.terracotta.org/forums/posts/list/5618.page#27960 дает базовое объяснение того, что некоторые люди придумали в качестве обходного пути, и

Фактический код, который они придумали. Подход действительно создает соглашение, которому нужно следовать, но было бы достаточно просто переопределить это своей собственной версией, если вам не нравится описанный фактический подход.

2 голосов
/ 05 июля 2013

В моем проекте я использовал ABC jar в XYZ war , оба реализовали ehCache с Spring 3.1, конфигурацию на основе xml (у нас есть ehCache.xml, а затем spring-context.xml, где мы перехватываем кеш через Spring AOP в обоих проектах).И мы получаем следующую ошибку:

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:] 

Решение:

Вот как мы решили эту проблему:

  1. Мы скопировали всеконфигурация кэша от ABCehCache.xml (из jar ABC) до XYZehCache.xml (из войны XYZ).
  2. Мы удалили ABCehCache.xml (из jar ABC), но всю конфигурацию (например, создание экземпляров bean для * 1022)* и Spring AOP) внутри ABC-spring.xml останутся прежними.
  3. В XYZ-spring.xml, мы импортировали ABC-spring.xml и определили менеджер составного кэша.

Поддерживаемые файлы конфигурации:

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" />
1 голос
/ 27 ноября 2015

Я бы рассмотрел следующие гораздо более простые альтернативы:

  1. Вариант 1: Аннотируйте ваши кэшируемые методы в служебном модуле с помощью @Cacheable, но позвольте приложению, в котором они находятся, создавать и настраивать кэши.В вашем примере вы должны объявить и настроить кэш 'getDataCache' в модуле приложения, даже если кеш используется в аннотации к классу, находящемуся в служебном модуле.
  2. Вариант 2: позволить служебному модулю создатьконфигурация кэша, но не сам менеджер кэша.Модуль приложения будет объединять конфигурации кеша из служебного (ых) модуля (ов) и самого приложения для создания одного менеджера кеша.

Мне не понравилось решение CompositeCacheManager , посколькуего поведение очень зависит от реализации базовых кэшей: он будет работать только так, как ожидается, если все базовые менеджеры кэша вернут нуль при неизвестном имени кэша.Некоторые реализации будут создавать их на лету, что приведет к кешированию с конфигурацией, которую вы не ожидали.

...