我正在使用ehcache作为缓存工具来处理spring 3.1注释缓存。
一个像这样的返回值的方法
@Cacheable("cache")
public MyObject getObj(Object param);
我第一次获得了myobject返回值,并且它是可编辑的。 ehcache可以通过设置“copyOnRead”或“copyOnWrite”来为此做些什么。 它会在读/写时强制序列化对象。 但是第一次spring不会从缓存中获取值,它总是通过方法本身返回。
是否有某种方法可以获得只读返回值?
答案 0 :(得分:3)
您可以编写自己的方面,始终创建返回值的副本,这将使您独立于某些Ehcache设置。
首先,像@CopyReturnValue
这样的标记注释很适合表达切入点:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CopyReturnValue {
}
现在,方面可以将此注释用于切入点表达式:
@Aspect
@Component
public class CopyReturnValueAspect {
@Around("@annotation(CopyReturnValue)")
public Object doCopyReturnValue(ProceedingJoinPoint pjp) throws Throwable {
Object retVal = pjp.proceed();
Object copy = BeanUtils.cloneBean(retVal); // create a copy in some way
return copy;
}
}
最后,将注释添加到方法中:
@CopyReturnValue
@Cacheable("cache")
public MyObject getObj(Object param);
对于CopyReturnValueAspect
,我使用BeanUtils
创建返回值的副本 - 仅作为示例。有关该主题的更多信息,您可能需要查看How to copy properties from one Java bean to another?
哦,不要忘记在Spring配置中启用@AspectJ支持,如果你还没有:
<aop:aspectj-autoproxy />
答案 1 :(得分:1)
我遇到了弹簧缓存的同样问题。我不想从缓存中接收相同的java对象。
在我的情况下,我想缓存具有许多字段的大型java对象,依此类推。因此,使用深层复制复制所有数据类非常痛苦。我阅读了有关使用序列化复制java对象的文章。
这让我想到只缓存序列化数据。每次从缓存中读取对象时,都会对其进行反序列化。
对于序列化,我使用了apache commons helper方法
@Override
public SerializedQuestions readUserQuestion(UID questionId, Locale locale) {
byte[] serializedData = readCachedUserQuestion(questionId, locale);
Object deserializedobject = org.apache.commons.lang.SerializationUtils.deserialize(serializedData);
return (SerializedQuestions) deserialize;
}
@Override
@Cacheable(value = SpringCacheKeys.USER_QUESTION_CACHE)
public byte[] readCachedUserQuestion(UID questionId, Locale locale) {
//read object from db
SerializedQuestions questions = new SerializedQuestions()
return org.apache.commons.lang.SerializationUtils.serialize(questions);
}
如果对 readCachedUserQuestion 的调用可能在同一个类中,则取决于弹簧配置。默认情况下,只缓存对方法的外部调用。
答案 2 :(得分:0)
我找到了一个对我有用的肮脏解决方案。通过创建另一个包含与返回的对象相同的属性的类,然后使用ModelMapper将返回的对象映射到我的新对象。 例如我有一个MyObject类:
public class MyObject {
private Long id;
private Long label;
//getters and setters
}
新创建的类:
public class MyObjectCopy {
private Long id;
private Long label;
//getters and setters
}
和一个返回MyObject的可缓存方法:
@Cacheable("cache")
public MyObject getMyObject();
并防止缓存被修改:我必须将该对象映射到我的classCopy上,然后对其进行处理:
MyObjectCopy myObjectCopy = modelMapper.map(myobject, MyObjectCopy.class);
不要忘记为嵌套对象创建一个副本类;