我在使用Spring缓存与ehcache时遇到了问题。由于某些原因,我的应用程序使用BeanFactories图形而不是ApplicationContexts。只要我们手动注册BeanPostProcessors,这种方法就一直运行良好,正如Spring文档中所述。
现在我们正在向应用程序添加缓存。当我们使用最简单的注释配置时,它可以工作。
// 这个有效
我们使用Spring XML配置这个bean工厂:
我们正在使用Spring 4.1.9和ehcache 2.10.2。以上代码运行良好。我们的“user” ehcache实例开始填充,因为我们得到了缓存失效,并返回击中的缓存值。一旦这个运行正确,我们发现不可能驱逐特定用户的所有条目,因为缓存键是权限ID和Map :: toString结果的连接。我们决定为每个用户创建一个缓存,以便更好地控制逐出。为了使用Spring,我们需要使用CacheResolver来完成这个任务。
我们通过添加一个新的bean定义来实现这个。
一旦我们这样做了,但是,当调用isAllowed方法时,会出现以下异常:
现在我们正在向应用程序添加缓存。当我们使用最简单的注释配置时,它可以工作。
// 这个有效
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
}
}
我们使用Spring XML配置这个bean工厂:
<?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 ...
我们正在使用Spring 4.1.9和ehcache 2.10.2。以上代码运行良好。我们的“user” ehcache实例开始填充,因为我们得到了缓存失效,并返回击中的缓存值。一旦这个运行正确,我们发现不可能驱逐特定用户的所有条目,因为缓存键是权限ID和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>
更改RoleManager中的注释为
@Cacheable(cacheResolver="myCacheResolver")
一旦我们这样做了,但是,当调用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类时,我发现它具有一个成员applicationContext,但该成员为空。
protected <T> T getBean(String beanName, Class<T> expectedType) {
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.applicationContext, expectedType, beanName);
}
在我看来,这似乎是Spring的一个Bug,因为我们并没有使用ApplicationContexts,但是缓存可以正常工作,直到我们需要使用CacheResolver。我已经查看了文档,没有提到必须使用ApplicationContexts才能使用Spring缓存抽象。
我的问题是,是否有人遇到过这个问题,如果有,你是如何解决的?我们绝对不能在我们的应用程序中使用ApplicationContexts,而我不想放弃一个完全可用的抽象,并直接使用ehcache(或JSR-107)APIs的代码。
提前感谢!