gpt4 book ai didi

java - Spring缓存支持需要ApplicationContext?

转载 作者:行者123 更新时间:2023-11-30 10:42:27 24 4
gpt4 key购买 nike

我在尝试在我的应用程序中使用带有 ehcache 的 Spring 缓存时遇到问题。由于我无法详细说明的原因,我的应用程序使用 BeanFactories 图而不是 ApplicationContexts。只要我们手动注册 BeanPostProcessors,这种方法就很有效,正如 Spring 文档中所指出的那样。

我们现在正在向应用添加缓存。当我们使用最简单的注解配置时,它就起作用了。

//这行得通

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 工厂使用 spring xml:

<?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

上面的代码工作得很好。我们的“用户”的 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>

并将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,该成员为 null。

protected <T> T getBean(String beanName, Class<T> expectedType) {
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.applicationContext, expectedType, beanName);
}

这对我来说似乎是 Spring 中的一个错误,因为我们不使用 ApplicationContexts,但是在我们需要使用 CacheResolver 之前缓存一直有效。我查看了文档,但没有提到必须使用 ApplicationContexts 才能使用 Spring 缓存抽象。

我想我的问题是,有没有人遇到过这个问题,如果遇到过,您是如何解决的?我们绝对不能在我们的应用程序中使用 ApplicationContexts,我宁愿不直接向 ehcache(或 JSR-107)API 抛出一个完美可用的抽象和代码。

提前致谢!

最佳答案

Spring 4.3 通过添加 setBeanFactory() 方法并使用 BeanFactory 从而设置为调用 CacheResolvers 解决了这个问题。不幸的是,我目前无法将我们的 Spring 库代码更新到 4.3,但是当我们将来能够升级时它会起作用。

关于java - Spring缓存支持需要ApplicationContext?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38128426/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com