アプリケーションでehcacheでSpringのキャッシュを使用しようとすると問題が発生しています。私が詳しく説明することができない理由から、私のアプリケーションはApplicationContextの代わりにBeanFactoriesのグラフを使用します。このアプローチは、Springのドキュメントでも指摘されているように、BeanPostProcessorsを手動で登録する限り、うまくいきました。SpringキャッシュのサポートにはApplicationContextが必要ですか?
キャッシングをアプリに追加しています。最も簡単なアノテーション設定を使用したときに動作します。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<cache:annotation-driven/>
<bean id="roleManager" class="com.x.y.z.RoleManager" scope="prototype"/>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManager"/>
</bean>
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="file:${conf.dir}/ehcache.xml"/>
<property name="shared" value="true"/>
</bean>
</beans>
... unrelated business beans elided ...
私たちは春の4.1.9とehcacheを2.10.2
を使用している:
//これは
package com.x.y.z;
public class RoleManager {
private String user;
public RoleManager(String user) {
this.user = user;
}
public String getName() {
return user;
}
@Cacheable("user")
public boolean isAllowed(String permissionId, Map<String,?> params)
{
... lengthy and expensive operation to determine if user is permitted to do something
}
}
我々はこのBeanの工場のための春のXMLを使用して、これを構成する作品上記のコードは非常にうまく動作します。私たちがキャッシュミスをしたときに、 "user"のehcacheインスタンスがいっぱいになり、ヒットのキャッシュ値が返されます。
これが正しく実行された後、キャッシュキーがpermissionidとMap :: toStringの結果を連結しているため、特定のユーザーのすべてのエントリを追い出すことができないことがわかりました。ユーザーごとにキャッシュを作成することにしました。 Springを使用するには、これを達成するためにCacheResolverを使用する必要があります。
package com.x.y.z;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.AbstractCacheResolver;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import java.util.Collection;
import java.util.Collections;
public class MyCacheResolver extends AbstractCacheResolver {
public MyCacheResolver() {
}
public MyCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
@Override
protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> cacheOperationInvocationContext) {
if(cacheOperationInvocationContext.getTarget() instanceof RoleManager) {
return Collections.singleton(((RoleManager) cacheOperationInvocationContext.getTarget()).getName());
}
return Collections.singleton("user");
}
}
私たちは、新しいBean定義
<bean id="myCacheResolver" class="com.x.y.z.MyCacheResolver">
<constructor-arg index="0" ref="cacheManager"/>
</bean>
を追加することによって、これをワイヤーと、我々はこれを行うたら
@Cacheable(cacheResolver="myCacheResolver")
にRoleManager内の注釈を変更するには、しかし、我々は以下の例外を取得しますisAllowedメソッドが呼び出されたとき:
java.lang.NullPointerException
at org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils.qualifiedBeanOfType(BeanFactoryAnnotationUtils.java:57)
at org.springframework.cache.interceptor.CacheAspectSupport.getBean(CacheAspectSupport.java:282)
at org.springframework.cache.interceptor.CacheAspectSupport.getCacheOperationMetadata(CacheAspectSupport.java:254)
at org.springframework.cache.interceptor.CacheAspectSupport.getOperationContext(CacheAspectSupport.java:226)
at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContexts.<init>(CacheAspectSupport.java:500)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy61.isAllowed(Unknown Source)
at com.x.y.z.RoleManager.isAllowed(CompositeRoleManager.java:61)
スタックトレースからCacheAspectSupportクラスを見ると、nullであるapplicationContextというメンバがあることがわかります。
protected <T> T getBean(String beanName, Class<T> expectedType) {
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.applicationContext, expectedType, beanName);
}
これは、我々がApplicationContextsを使用していないので、私には春のバグのように思える、と私たちはCacheResolverを使用する必要があるまでは、まだ作品をキャッシュします。ドキュメントを見てきましたが、Springのキャッシュ抽象化を使用するためにApplicationContextを使用しなければならないという言葉はありません。
私の質問は誰でもこの問題を経験していると思いますが、もしそうなら、あなたはそれを解決するために何をしましたか?私たちのアプリケーションではApplicationContextを絶対に使用することはできません.ehcache(またはJSR-107)APIには、完全に使用可能な抽象化とコードを直接投げ捨ててはいけません。
ありがとうございます!
Spring 4.3がCacheAspectSupportクラスにsetBeanFactory()メソッドを追加し、setApplicationContext()メソッドを非推奨にしたようです。変更に対応するJIRAの問題を見つけることができませんでしたが、私のコードがSpring 4.3で動作することを確認しました – user2729944