31

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

所以Util-Module会有这样的事情:


数据管理器.java

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

数据管理器-ehcache.xml

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

数据管理器-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) { ... }
...

我的应用程序 ehcache.xml

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

我的应用程序弹簧配置.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"/>
...

问题:

是否可以在主项目和依赖模块中使用注释驱动的缓存,同时保持配置分离?

如果不是,请解释为什么不这样做。如果是这样,将不胜感激对上述配置中需要更改的内容的解释。

4

5 回答 5

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>
于 2012-02-08T10:00:52.973 回答
9

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

于 2012-02-03T09:42:47.743 回答
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提供了一些人提出的解决方法的基本解释,并且

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

于 2012-01-20T02:36:39.847 回答
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 war)。
  2. 我们删除了ABCehCache.xml(从 ABC jar 中),但里面的所有配置(如 bean 实例化ehCache.xml和 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" />
于 2013-07-05T07:55:53.280 回答
1

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

  1. 选项 1:使用 @Cacheable 在实用程序模块中注释您的可缓存方法,但让封闭的应用程序创建和配置缓存。在您的示例中,您将在应用程序模块中声明和配置缓存“getDataCache”,即使缓存用于对驻留在实用程序模块中的类的注释。
  2. 选项 2:让实用程序模块创建缓存配置,而不是缓存管理器本身。应用程序模块将结合实用程序模块和应用程序本身的缓存配置来创建单个缓存管理器。

我不喜欢CompositeCacheManager的解决方案,因为它的行为非常依赖于底层缓存的实现:只有当所有底层缓存管理器在未知缓存名称上返回 null 时,它才会按预期工作。一些实现会即时创建它们,从而产生具有您未预料到的配置的缓存。

于 2015-11-27T15:32:57.097 回答