Использование аннотации кэша Spring в нескольких модулях
у меня есть модуль util, который производит банку для использования в других приложениях. Я хотел бы, чтобы этот модуль использовал кэширование и предпочел бы использовать Spring's annotation-driven
кэширование.
так Util-Module
будет что-то вроде этого:
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"/>
...
Я бы тоже как и мой развертываемый блок, чтобы иметь кэширование через аннотацию Spring, включая вышеупомянутый jar в качестве зависимости. Так что мой Deployable-Unit
будет что-то вроде этого:
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"/>
...
вопрос:
можно ли использовать кэширование аннотаций как в вашем основном проекте, так и в модуль зависимостей при разделении конфигураций?
если нет, объяснение того, почему это не было бы оценено. Если это так, то было бы оценено объяснение того, что необходимо изменить в приведенной выше конфигурации.
5 ответов
Это, кажется, исправлено в 3.2M1, см. https://jira.springsource.org/browse/SPR-8696
используйте этот класс: 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>
Spring в настоящее время ожидает, что cacheManager будет Одноэлементным. Это то, с чем столкнулся проект 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 обеспечивает базовое объяснение что некоторые люди придумали, как обойти и
- http://itcb.svn.sourceforge.net/viewvc/itcb/addons/itcb-cache/trunk/
- http://itcb.svn.sourceforge.net/.../itcb/addons/cachemanager/
Это фактический код, который они придумали. Этот подход создает соглашение, но было бы достаточно легко переопределить его с помощью вашей собственной версии, если вам не нравится фактический подход описанный.
в моем проекте я использую ABC jar внутри XYZ война, как реализация ehCache с Spring 3.1, xml-управляемая конфигурация(у нас есть ehCache.xml, а затем spring-контекст.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$43481.getContentById(<generated>) [cglib-2.2.2.jar:]
устранение:
вот как мы решили эту проблему:
- мы скопировали вся конфигурация кэша из
ABCehCache.xml
(от ABC jar) доXYZehCache.xml
(из XYZ войны). - мы удалены
ABCehCache.xml
(из ABC jar), но вся конфигурация(например, экземпляр bean дляehCache.xml
и пружина AOP) внутриABC-spring.xml
останется прежним. - на
XYZ-spring.xml
, мы импортировалиABC-spring.xml
и определенный составной менеджер кэша.
поддерживаемые файлы конфигурации:
ABC-весна.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-весна.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: Аннотируйте свои кэшируемые методы в служебном модуле с помощью @Cacheable, но позвольте вложенному приложению создавать и настраивать кэши. В вашем примере вы объявите и настроите кэш "getDataCache" в модуле приложения, даже если кэш используется в аннотации к классу, находящемуся в модуле утилиты.
- Вариант 2: пусть модуль утилиты создаст конфигурацию кэша, но не сам менеджер кэша. Модуль приложения будет объединять конфигурации кэша из модуля (модулей) утилиты и самого приложения для создания единого диспетчера кэша.
Мне не понравилось решение CompositeCacheManager, поскольку его поведение очень зависит от реализации базовых кэшей: он будет работать только так, как ожидалось, если все базовые менеджеры кэша вернут null на неизвестное имя кэша. Некоторые реализации создавали бы их на лету, в результате чего кэши с конфигурацией, которую вы не ожидали.