2016-06-30 2 views
2

내 응용 프로그램에서 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에 직접 버리지는 않을 것입니다.

미리 감사드립니다.

+0

스프링 4.3은 CacheAspectSupport 클래스에 setBeanFactory() 메소드를 추가하고 setApplicationContext() 메소드를 사용하지 않는 것 같습니다.JIRA에서 변경 사항에 해당하는 문제를 찾을 수 없었지만 Spring 4.3에서 코드가 작동하는지 확인했습니다. – user2729944

답변

1

스프링 4.3에서는 setBeanFactory() 메소드를 추가하고 CacheResolvers를 호출하도록 설정된 BeanFactory를 사용하여 문제를 해결했습니다. 불행하게도 현재 스프링 라이브러리 코드를 4.3으로 업데이트 할 수는 없지만 향후 업그레이드가 가능할 때 작동 할 것입니다.

관련 문제