在多个模块中使用Spring缓存注释

时间:2011-12-28 16:50:38

标签: spring caching annotations ehcache spring-annotations

我有一个util模块,可以生成一个可以在其他应用程序中使用的jar。我希望这个模块使用缓存,并且更喜欢使用Spring的annotation-driven缓存。

所以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) { ... }
...

我-APP-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 个答案:

答案 0 :(得分:13)

使用此课程: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>

答案 1 :(得分:9)

这似乎在3.2M1中已修复,请参阅https://jira.springsource.org/browse/SPR-8696

答案 2 :(得分:5)

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提供了一些基础解释,说明了某些人提出的解决方法和

他们想出的实际代码是什么。该方法确实创建了一个遵循的约定,但如果您不喜欢所描述的实际方法,则可以使用您自己的版本重新实现它。

答案 3 :(得分:2)

在我的项目中,我一直在 XYZ war 中使用 ABC jar ,两者都使用Spring 3.1实现 ehCache,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(从ABC jar)复制到XYZehCache.xml(来自XYZ战争)。
  2. 我们删除了ABCehCache.xml(来自ABC jar),但ehCache.xml内的所有配置(如ABC-spring.xml和Spring AOP的bean实例化)都将保持不变。
  3. XYZ-spring.xml中,我们导入了ABC-spring.xml并定义了复合缓存管理器。
  4. 支持的配置文件:

    <强> 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" />
    

答案 4 :(得分:1)

我会考虑以下更简单的替代方案:

  1. 选项1:使用@Cacheable在实用程序模块中注释可缓存的方法,但让封闭的应用程序创建和配置缓存。在您的示例中,您将在app模块中声明并配置缓存“getDataCache”,即使缓存用于注释到驻留在实用程序模块中的类。
  2. 选项2:让实用程序模块创建缓存配置,但不创建缓存管理器本身。应用程序模块将组合来自实用程序模块的缓存配置和应用程序本身,以创建单个缓存管理器。
  3. 我不喜欢 CompositeCacheManager 的解决方案,因为它的行为非常依赖于底层缓存的实现:只有当所有底层缓存管理器在未知缓存名称上返回null时,它才会按预期工作。有些实现会动态创建它们,从而产生具有您不期望的配置的缓存。