`
hanqunfeng
  • 浏览: 1526313 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

使用Spring3.1 Cache注解+EHCache遇到的问题

 
阅读更多

关于Spring3.1 Cache注解的介绍请参看http://hanqunfeng.iteye.com/blog/1158824

 

这里只说一下遇到的问题,web应用,session超时为30分钟,使用Cache注解+EHCache,如下:

 
<cache name="andCache" maxElementsInMemory="10000"  
        maxElementsOnDisk="1000" eternal="false" overflowToDisk="true"  
        diskSpoolBufferSizeMB="20" timeToIdleSeconds="300" timeToLiveSeconds="600"  
        memoryStoreEvictionPolicy="LFU" />  

说明:缓存名andCache,内存中最多可缓存10000个Element,其中的element会在闲置5分钟或是存活10分钟之后失效,

超过10000element时,element将会输出到磁盘中。

 

结果,在登录系统后,如果超过5分钟不访问系统,则会出现异常,

按照这样配置,我原以为,如果5分钟之内不访问应用,则缓存会失效,那么spring就会重新执行原先被缓存的方法,但实际上,方法并没有被重新执行,而是返回了null,貌似spring依旧是从缓存中查找,并且找到了key,只不过value已经是null了。

 

这样就会导致系统出现空指针异常,况且session也尚未超时,

但就算是将闲置时间设置为30分钟以上,用户在下次登录时一样会出现异常,但是第二次登录就又会正常,然后周而复始,貌似,只有当第一次取到null后,spring才会重新执行方法。

 

感觉上,好像ehcache清除缓存后,spring并不知道,因为key依旧可以在spring的cache中找到,但是通过key取值时,spring会从ehcache中查找,由于ehcache已经清除了缓存,所以返回值一定是null,而spring也把这个null当成了被缓存的value返回给系统。

 

使用spring自带的缓存机制没有遇到该问题。

 

分享到:
评论
5 楼 xiaoyaozjl 2013-04-08  
LZ使用的是spring 3.1.0.M1版本,也就是里程碑版本非正式版,是存在这个问题的。在spring 3.1.0.M2里面已经修正了。

3.1.0.M1版本的org.springframework.cache.ehcache.EhCacheCache.java:
public Object get(Object key) {
	Element element = cache.get(key);
	return (element != null ? element.getObjectValue() : null);
}


3.1.0.M2版本的org.springframework.cache.ehcache.EhCacheCache.java:
public ValueWrapper get(Object key) {
	Element element = cache.get(key);
	return (element != null ? new DefaultValueWrapper<Object>(element.getObjectValue()) : null);
}
4 楼 yaofaye 2013-02-26  
对的,返回的null是,key对应的value值为null,并不是Cache.ValueWrapper为null,客户端判断一下value值,如果为null,返回一个null的Cache.ValueWrapper即可。
songbin0201 写道
引用
但实际上,方法并没有被重新执行,而是返回了null,貌似spring依旧是从缓存中查找,并且找到了key,只不过value已经是null了。


从源码上看不应该是这样吧?
代理方法会拦截并判断Cache.ValueWrapper是否为空,如果为空直接invoke原方法,返回原方法中查询出来的对象

// follow up with cacheable
//inspectCacheables根据cachename验证Cache.ValueWrapper是否为空
CacheStatus status = inspectCacheables(ops.get(CACHEABLE));

Map<CacheOperationContext, Object> updates = inspectCacheUpdates(ops.get(UPDATE));

if (status != null) {
if (status.updateRequired) {
   updates.putAll(status.cUpdates);
}
// return cached object
else {
   return status.retVal;
}
}

retVal = invoker.invoke();//retVal如果为空,直接调用原方法,返回非缓存数据



inspectCacheables方法中关于验证Cache.ValueWrapper的代码,为空设置localCacheHit 为false,localCacheHit为false,设置需要重新更新cache

boolean localCacheHit = false;

					// check whether the cache needs to be inspected or not (the method will be invoked anyway)
					if (!updateRequire) {
						for (Cache cache : context.getCaches()) {
							Cache.ValueWrapper wrapper = cache.get(key);
							if (wrapper != null) {
								retVal = wrapper.get();
								localCacheHit = true;
								break;
							}
						}
					}

					if (!localCacheHit) {
						updateRequire = true;
					}

3 楼 songbin0201 2012-12-17  
引用
但实际上,方法并没有被重新执行,而是返回了null,貌似spring依旧是从缓存中查找,并且找到了key,只不过value已经是null了。


从源码上看不应该是这样吧?
代理方法会拦截并判断Cache.ValueWrapper是否为空,如果为空直接invoke原方法,返回原方法中查询出来的对象

// follow up with cacheable
//inspectCacheables根据cachename验证Cache.ValueWrapper是否为空
CacheStatus status = inspectCacheables(ops.get(CACHEABLE));

Map<CacheOperationContext, Object> updates = inspectCacheUpdates(ops.get(UPDATE));

if (status != null) {
if (status.updateRequired) {
   updates.putAll(status.cUpdates);
}
// return cached object
else {
   return status.retVal;
}
}

retVal = invoker.invoke();//retVal如果为空,直接调用原方法,返回非缓存数据



inspectCacheables方法中关于验证Cache.ValueWrapper的代码,为空设置localCacheHit 为false,localCacheHit为false,设置需要重新更新cache

boolean localCacheHit = false;

					// check whether the cache needs to be inspected or not (the method will be invoked anyway)
					if (!updateRequire) {
						for (Cache cache : context.getCaches()) {
							Cache.ValueWrapper wrapper = cache.get(key);
							if (wrapper != null) {
								retVal = wrapper.get();
								localCacheHit = true;
								break;
							}
						}
					}

					if (!localCacheHit) {
						updateRequire = true;
					}

2 楼 jahu 2012-12-15  
登录用户,不用缓存吧,
 
1 楼 snowolf 2012-09-24  
多个应用,分布式部署,缓存数据如何保持一致性?

相关推荐

Global site tag (gtag.js) - Google Analytics