web-dev-qa-db-ja.com

複数のモジュールでSpringキャッシュアノテーションを使用する

他のアプリケーションで使用するjarを生成するutilモジュールがあります。このモジュールでキャッシングを使用したいので、Springの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"/>
...

また、上記のjarを依存関係として含めながら、デプロイ可能なユニットにSpringアノテーションを介したキャッシュを持たせたいと思います。したがって、私の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"/>
...

質問:

構成を分離したまま、メインプロジェクトと依存関係モジュールの両方でアノテーション駆動型キャッシュを使用することは可能ですか?

そうでない場合は、なぜそうではないのかを説明していただければ幸いです。その場合、上記の構成で何を変更する必要があるかについての説明をいただければ幸いです。

31
Snekse

これは3.2M1で修正されているようです。 https://jira.springsource.org/browse/SPR-8696 を参照してください。

9
bgranvea

このクラスを使用: 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>
13

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#2796 は、一部の人々が回避策として思いついた基本的な説明を提供し、

彼らが思いついた実際のコードです。このアプローチは従うべき規則を作成しますが、説明されている実際のアプローチが気に入らない場合は、独自のバージョンでこれを再実装するのは簡単です。

5
Joe

私のプロジェクトでは、ABC jar内でXYZ warを使用しており、両方ともSpring 3.1、xml駆動型構成のehCache(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およびSpringAOPのBeanインスタンス化など)は同じままです。
  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" />
2
ritesh

次のはるかに簡単な代替案を検討します。

  1. オプション1:ユーティリティモジュールのキャッシュ可能なメソッドに@Cacheableアノテーションを付けますが、囲んでいるアプリにキャッシュを作成して構成させます。この例では、ユーティリティモジュールにあるクラスへのアノテーションでキャッシュが使用されている場合でも、アプリモジュールでキャッシュ 'getDataCache'を宣言して構成します。
  2. オプション2:ユーティリティモジュールにキャッシュ構成を作成させますが、キャッシュマネージャー自体は作成させません。アプリモジュールは、ユーティリティモジュールのキャッシュ構成とアプリ自体を組み合わせて、単一のキャッシュマネージャーを作成します。

CompositeCacheManagerのソリューションは、その動作が基になるキャッシュの実装に大きく依存しているため、気に入らなかった。基になるすべてのキャッシュマネージャーが不明なキャッシュ名でnullを返した場合にのみ、期待どおりに機能する。一部の実装では、それらをオンザフライで作成するため、予期しない構成のキャッシュが生成されます。

1
Alexander