首页 文章

如何防止缓存中的返回值在spring cacheable中更改

提问于
浏览
1

我正在使用ehcache作为缓存工具处理spring 3.1注释缓存 .

一个像这样返回值的方法

@Cacheable("cache")
public MyObject getObj(Object param);

我第一次得到myobject返回值,它是可编辑的 . ehcache可以通过设置“copyOnRead”或“copyOnWrite”来为此做些什么 . 它会在读/写时强制序列化对象 . 但是第一次spring不会从缓存中获取值,它总是通过方法本身返回 .

有没有办法获得只读返回值?

2 回答

  • 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

    我遇到了 spring 缓存的同样问题 . 我不想从缓存中收到相同的java对象 .

    在我的情况下,我想缓存具有许多字段的大型java对象,依此类推 . 因此,使用深层复制复制所有数据类非常痛苦 . 我阅读了有关使用序列化复制Java对象的文章 .

    http://www.javaworld.com/article/2077578/learn-java/java-tip-76--an-alternative-to-the-deep-copy-technique.html

    这让我想到只缓存序列化数据 . 每次从缓存中读取对象时,都会对其进行反序列化 .

    对于序列化,我使用了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的调用可能在同一个类中,则它取决于spring配置 . 默认情况下,只缓存对方法的外部调用 .

相关问题