Java 缓存完整性问题
我有一个使用ehcache进行缓存的应用程序(但我认为这个问题与框架无关),它有一个方法拦截器,所以基本上如果我将我的方法标记为缓存,就会发生如下情况:Java 缓存完整性问题,java,caching,pass-by-reference,ehcache,Java,Caching,Pass By Reference,Ehcache,我有一个使用ehcache进行缓存的应用程序(但我认为这个问题与框架无关),它有一个方法拦截器,所以基本上如果我将我的方法标记为缓存,就会发生如下情况: public Object invoke(MethodInvocation mi) throws Throwable { Object result = cache.get(key); //key comes from MethodInvocation processing if (result
public Object invoke(MethodInvocation mi) throws Throwable {
Object result = cache.get(key);
//key comes from MethodInvocation processing
if (result == null) {
result = mi.proceed();
cache.put(key, result);
}
return result;
}
到目前为止还不错。我正在缓存一个方法,该方法返回一个数组
,调用方式如下:
List<Object> result = methodWithCaching();
result.add(new Object()); //!
List result=methodWithCaching();
结果。添加(新对象());/!
可以想象,标有的行代码>还更新缓存实例,这不是我想要的
有人能想出一种方法来停止这种行为而不修改客户端,只修改拦截器吗?你说的“更新缓存”是什么意思?您是否担心用户可以修改methodWithCaching()返回的列表?如果是这样,我建议该方法返回一个不可修改的集合。或者,缓存可能会检测到结果是一个集合,并使用不可修改的包装将其包装。我的理解是,您希望拦截器返回缓存结果的副本,以便任何客户端修改都只会影响副本
老实说,我想不出一个好的、通用的方法来做到这一点。丑陋的是依赖于clone()
,或者每次都创建一个新列表
听起来你真的应该修改客户端,如果可能的话。问题是我不能创建新对象。我当然不能调用clone
,因为它是受保护的方法。而且返回值可以是任何东西,而不仅仅是列表。正如我所说,没有好的解决方案<代码>克隆()
被设计破坏;您需要执行if(result instanceof Cloneable)
操作,然后通过反射调用clone()
。我希望用户可以对列表执行任何操作。但是想象一下这个场景:methodinvocation(1),cache miss,userupdates列表,并且缓存也得到更新。methodinvocation(2),缓存命中(现在列表包含1个元素),用户更新列表,缓存也得到更新。methodinvocation(3)、cache hit(现在列表包含2个元素)等等。您希望用户拥有缓存对象的本地副本而不是共享实例吗?没错,而且可能在不修改客户端的情况下,只是interceptorI会尝试使用akhnaten建议的Cloneable实现某些东西。你要么返回数据的副本,要么同时返回不同的数据结构。我不能。实现Cloneable
不会使clone()
方法公开。我必须在我想要缓存的每个对象中自己实现这一点