내 응용 프로그램에서 ehcache와 함께 Spring 캐싱을 사용하는 데 문제가 있습니다. 이유를 설명 할 수 없기 때문에, 내 애플리케이션은 ApplicationContext 대신 BeanFactories의 그래프를 사용한다. 이 접근법은 스프링 문서에서 언급 한 것처럼 BeanPostProcessors를 수동으로 등록하는 한 잘 작동합니다.스프링 캐시 지원에는 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
}
}
우리는이 빈 공장에 대한 스프링 XML을 사용하여이를 구성 작업 위의 코드는 꽤 잘 작동합니다. "사용자"에 대한 우리의 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 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 멤버가 있음을 알 수 있습니다. 우리가 CacheResolver를 사용해야 할 때까지 우리가 작품을 캐싱 아직 ApplicationContexts 내 등을 사용하지 않기 때문에
protected <T> T getBean(String beanName, Class<T> expectedType) {
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.applicationContext, expectedType, beanName);
}
이 나에게 봄의 버그처럼 보인다. 나는 문서를 살펴 봤고 스프링 캐싱 추상화를 사용하기 위해서는 ApplicationContexts를 사용해야한다는 언급이 없다.
제 질문은 누구나이 문제를 경험 한 것입니다. 그렇다면 문제를 해결하기 위해 무엇을 했습니까? 우리는 우리 애플리케이션에서 ApplicationContexts를 절대 사용할 수 없으며, 완벽하게 사용할 수있는 추상화 및 코드를 ehcache (또는 JSR-107) API에 직접 버리지는 않을 것입니다.
미리 감사드립니다.
스프링 4.3은 CacheAspectSupport 클래스에 setBeanFactory() 메소드를 추가하고 setApplicationContext() 메소드를 사용하지 않는 것 같습니다.JIRA에서 변경 사항에 해당하는 문제를 찾을 수 없었지만 Spring 4.3에서 코드가 작동하는지 확인했습니다. – user2729944